我认为在继承的情况下,您必须亲自实现Coding
。也就是说,您必须在超类和子类中指定CodingKeys
,并实现init(from:)
和encode(to:)
。根据WWDC视频(大约在49:28左右,如下图所示),您必须使用超级编码器/解码器调用super。
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
myVar = try container.decode(MyType.self, forKey: .myVar)
let superDecoder = try container.superDecoder()
try super.init(from: superDecoder)
}
视频似乎没有展示编码部分(但对于
encode(to:)
部分,它使用的是
container.superEncoder()
),但在您的
encode(to:)
实现中,它的工作方式基本相同。我可以确认这在这个简单案例中有效(请参见下面的演示代码)。
我仍然在尝试解决一个更复杂的模型的一些奇怪行为,我正在将它从
NSCoding
转换过来,该模型有许多新的嵌套类型(包括
struct
和
enum
),显示出意外的
nil
行为,这“不应该”出现。只要意识到可能涉及嵌套类型的边缘情况即可。
编辑: 我在测试场景中发现嵌套类型正常运作。我现在怀疑存在某些自引用类的问题(考虑树节点的子代),其集合本身也包含该类的各种子类的实例。简单的自引用类的测试解码正常(即,没有子类),因此我现在集中精力研究为什么子类的案例失败。
更新:2017年6月25日: 最终我向苹果报告了这个错误。rdar://32911973-不幸的是,对于包含
Subclass: Superclass
元素的
Superclass
数组进行编码/解码循环将导致数组中的所有元素都被解码为
Superclass
(子类的
init(from:)
从未被调用,导致数据丢失或更糟)。
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
中恢复了超类和子类属性。