Наследование кодируемого класса

Я пишу программу, используя Swift 4 и Xcode 9.2. Я столкнулся с трудностями при написании кодируемого класса (именно класса, а не структуры). Когда я пытаюсь наследовать один класс от другого, JSONEncoder не берет все свойства из подкласса (дочернего). Пожалуйста, посмотрите на это:

class BasicData: Encodable {

    let a: String
    let b: String

    init() {
        a = "a"
        b = "b"
    }
}

class AdditionalData: BasicData {

    let c: String

    init(c: String) {
        self.c = c
    }

}

let encode = AdditionalData(c: "c")

do {
    let data = try JSONEncoder().encode(encode)
    let string = String(data: data, encoding: .utf8)
    if let string = string {
        print(string)
    }
} catch {
}

Он напечатает это: {"a":"a","b":"b"}

Но мне нужно это: {"a":"a","b":"b","c":"c"}

Похоже, что c свойство класса AdditionalData просто куда-то и как-то потерялось.

Итак, вопрос: если у меня есть класс, подписанный протоколом Encodable, как правильно сделать класс подкласса (дочерний класс, наследующий)?

Буду благодарен за любую помощь или совет.


person Alex    schedule 13.01.2018    source источник


Ответы (2)


Encodable и Decodable включают некоторый синтез кода, когда компилятор по существу пишет код за вас. Когда вы согласовываете BasicData с Encodable, эти методы записываются в класс BasicData и, следовательно, они не знают о каких-либо дополнительных свойствах, определенных подклассами. Вы должны переопределить метод encode(to:) в своем подклассе:

class AdditionalData: BasicData {
    let c: String
    let d: Int

    init(c: String, d: Int) {
        self.c = c
        self.d = d
    }

    private enum CodingKeys: String, CodingKey {
        case c, d
    }

    override func encode(to encoder: Encoder) throws {
        try super.encode(to: encoder)
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(self.c, forKey: .c)
        try container.encode(self.d, forKey: .d)
    }
}

См. этот вопрос для аналогичной проблемы с Decodable.

person Code Different    schedule 14.01.2018
comment
Спасибо за помощь, все работает! Я отмечу его как принятый. А не могли бы вы, если не трудно, отредактировать свой код и добавить свойство d типа Int в класс AdditionalData? Будет очень интересно посмотреть, как будут кодироваться некоторые свойства. Что для этого делать? - person Alex; 15.01.2018
comment
Ваш ответ ИДЕАЛЬНЫЙ. Последние два дня я застрял с проблемой, и ваш ответ спас мне всю оставшуюся жизнь;) - person Milad Faridnia; 04.03.2018
comment
Привет, как я могу сделать эту часть многоразовой? Любая идея частного перечисления CodingKeys: String, CodingKey { case c, d } переопределить func encode (для кодировщика: Encoder) throws { try super.encode (для: кодировщика) var container = encoder.container (keyedBy: CodingKeys.self) try container .encode(self.c, forKey: .c) попробуйте container.encode(self.d, forKey: .d) } - person Yogesh Patel; 13.05.2020

в моем случае базовый класс не обязательно должен быть Codable. Только подклассы должны быть Codable. В этом случае не объявляйте базовый класс как Codable, а только подклассы. При этом вам не нужно делать какие-либо шаблонные вещи encode/codingKeys/init(from: Decoder). Надеюсь, это поможет некоторым людям.

person Marc Blanchet    schedule 23.07.2020