Использование «Codable» для установки значений свойств не работает через наследование - PullRequest
0 голосов
/ 29 апреля 2018

Я не могу установить свойство b в дочернем классе. Это родительский класс, который наследуется от Codable, и, кажется, работает хорошо.

Я чувствую, что упускаю что-то действительно очевидное, но мне трудно видеть древесину для деревьев.

Ниже приведен пример моей проблемы на игровой площадке. b остается 0, несмотря на то, что установлено на 10. Это дочерний класс, который передается, но родительское свойство, которое может быть установлено (очень странно!).

class Primary : Codable {
    var a: Int = 0
}

class Secondary : Primary {
    var b: Int = 0
}

let c = Secondary.self

func testRef<T: Codable>(_ t: T.Type) {
    let json = "{\"a\":5, \"b\" : 10}".data(using: .ascii)!
    let testCodable = try? JSONDecoder().decode(t.self, from: json)
    print("a >> \((testCodable as! Primary).a)")
    print("b >> \((testCodable as! Secondary).b)")
}

testRef(c)

Вывод этого:

a >> 5
b >> 0

Любые советы или указатели будут с благодарностью приняты.

  • пробовал в Xcode 9.3, Swift 4.1

1 Ответ

0 голосов
/ 29 апреля 2018

Магия Codable основана на простоте (использование структур, не поддерживающих наследование).

Чем больше пользовательских, тем больше кода

Вы должны написать собственный инициализатор в подклассе , чтобы учесть наследование (спасибо Хэмишу за примечание, что CodingKeys и инициализатор синтезированы в базовом классе), я намеренно пропустил часть Encodable

class Primary : Decodable {
    var a: Int

/*
   private enum CodingKeys: String, CodingKey { case a }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        a = try container.decode(Int.self, forKey: .a)
    }
*/
}

class Secondary : Primary {
    var b: Int

    private enum CodingKeys: String, CodingKey { case b }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        b = try container.decode(Int.self, forKey: .b)
        try super.init(from: decoder)
    }
}


func testRef<T: Decodable>() throws -> T {
    let json = "{\"a\":5, \"b\" : 10}".data(using: .utf8)!
    return try JSONDecoder().decode(T.self, from: json)
}

do {
    let secondary : Secondary = try testRef()
    print(secondary.a, secondary.b) // 5 10
} catch { print(error) }
...