我相信在继承的情况下你必须自己实现Coding。也就是说,您必须在超类和子类中指定CodingKeys 并实现init(from:) 和encode(to:)。根据WWDC video(大约 49:28,如下图),您必须使用 super 编码器/解码器调用 super。
required init(from decoder: Decoder) throws {
// Get our container for this subclass' coding keys
let container = try decoder.container(keyedBy: CodingKeys.self)
myVar = try container.decode(MyType.self, forKey: .myVar)
// otherVar = ...
// Get superDecoder for superclass and call super.init(from:) with it
let superDecoder = try container.superDecoder()
try super.init(from: superDecoder)
}
视频似乎没有显示编码方面(但它是container.superEncoder() 用于encode(to:) 方面),但它在您的encode(to:) 实现中的工作方式大致相同。我可以确认这在这个简单的情况下有效(参见下面的操场代码)。
我自己仍在为一些奇怪的行为而苦苦挣扎,我正在使用从 NSCoding 转换而来的更复杂的模型,该模型具有许多新嵌套的类型(包括 struct 和 enum),这些类型表现出这种意外nil 行为和“不应该”。请注意,可能存在涉及嵌套类型的边缘情况。
编辑: 嵌套类型似乎在我的测试操场上运行良好;我现在怀疑自引用类(想想树节点的子节点)有问题,它本身的集合还包含该类的各种子类的实例。一个简单的自引用类的测试可以很好地解码(即没有子类),所以我现在将精力集中在子类案例失败的原因上。
2017 年 6 月 25 日更新:我最终向 Apple 提交了一个关于此问题的错误。 rdar://32911973 - 不幸的是,包含Subclass: Superclass 元素的Superclass 数组的编码/解码循环将导致数组中的所有元素都被解码为Superclass(永远不会调用子类'init(from:),导致数据丢失或更糟)。
//: Fully-Implemented Inheritance
class FullSuper: Codable {
var id: UUID?
init() {}
private enum CodingKeys: String, CodingKey { case id }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(UUID.self, forKey: .id)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
}
}
class FullSub: FullSuper {
var string: String?
private enum CodingKeys: String, CodingKey { case string }
override init() { super.init() }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let superdecoder = try container.superDecoder()
try super.init(from: superdecoder)
string = try container.decode(String.self, forKey: .string)
}
override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(string, forKey: .string)
let superencoder = container.superEncoder()
try super.encode(to: superencoder)
}
}
let fullSub = FullSub()
fullSub.id = UUID()
fullSub.string = "FullSub"
let fullEncoder = PropertyListEncoder()
let fullData = try fullEncoder.encode(fullSub)
let fullDecoder = PropertyListDecoder()
let fullSubDecoded: FullSub = try fullDecoder.decode(FullSub.self, from: fullData)
超类和子类属性都在fullSubDecoded 中恢复。