类继承的使用是否破坏了类的可解码性。例如,下面的代码
class Server : Codable {
var id : Int?
}
class Development : Server {
var name : String?
var userId : Int?
}
var json = "{\"id\" : 1,\"name\" : \"Large Building Development\"}"
let jsonDecoder = JSONDecoder()
let item = try jsonDecoder.decode(Development.self, from:json.data(using: .utf8)!) as Development
print(item.id ?? "id is nil")
print(item.name ?? "name is nil") here
输出为:
1
name is nil
现在如果我把这个反过来,name可以解码,但id不能。
class Server {
var id : Int?
}
class Development : Server, Codable {
var name : String?
var userId : Int?
}
var json = "{\"id\" : 1,\"name\" : \"Large Building Development\"}"
let jsonDecoder = JSONDecoder()
let item = try jsonDecoder.decode(Development.self, from:json.data(using: .utf8)!) as Development
print(item.id ?? "id is nil")
print(item.name ?? "name is nil")
输出为:
id is nil
Large Building Development
你不能在两个类中都表达Codable。
7条答案
按热度按时间goucqfw61#
我相信在继承的情况下,你必须自己实现
Coding
。也就是说,必须指定CodingKeys
,并在超类和子类中实现init(from:)
和encode(to:)
。根据WWDC video(大约49:28,如下图所示),您必须使用super编码器/解码器调用super。视频似乎没有显示编码端(但它是
encode(to:)
端的container.superEncoder()
),但它在encode(to:)
实现中的工作方式大致相同。我可以在这个简单的例子中确认这是可行的(参见下面的playground代码)。我自己仍然在与一些奇怪的行为作斗争,我正在从
NSCoding
转换一个更复杂的模型,它有很多新嵌套的类型(包括struct
和enum
),这些类型表现出这种意想不到的nil
行为和“不应该”。请注意,可能存在涉及嵌套类型的边缘情况。**编辑:**嵌套类型似乎在我的测试操场上工作得很好;我现在怀疑自引用类(想想树节点的子节点)有什么问题,它的集合本身也包含该类的各种子类的示例。对一个简单的自引用类的测试可以很好地解码(也就是说,没有子类),所以我现在将精力集中在子类失败的原因上。
**更新6月25 '17:**我最终向苹果提交了一个关于这个问题的bug。rdar://32911973 -不幸的是,包含
Subclass: Superclass
元素的Superclass
数组的编码/解码周期将导致数组中的所有元素都被解码为Superclass
(子类'init(from:)
永远不会被调用,导致数据丢失或更糟)。在
fullSubDecoded
中,超级和子类属性都被恢复。ia2d9nvy2#
Found This Link - Go down to inheritance section
为了解码,我这样做了:
mwyxok5s3#
Swift在5.1中引入了Property Wrappers,我实现了一个名为**SerializedSwift的库,它使用了property wrappers的功能来将JSON数据解码和编码为对象。
我的主要目标之一是,让继承的对象开箱即用**,而不需要额外的
init(from decoder: Decoder)
重写。它还支持自定义编码键、备用键、默认值、自定义转换类以及未来将包含的更多功能。
支持GitHub (SerializedSwift)。
dfddblmv4#
我可以通过使我的基类和子类符合
Decodable
而不是Codable
来使它工作。如果我使用Codable
,它会以奇怪的方式崩溃,例如在访问子类的字段时得到EXC_BAD_ACCESS
,但调试器可以显示所有子类值而没有问题。此外,将superDecoder传递给
super.init()
中的基类也不起作用。我只是把解码器从子类传递到基类。41zrol4v5#
用下面的方法怎么样?
关于组成的其他信息:http://mikebuss.com/2016/01/10/interfaces-vs-inheritance/
0yg35tkg6#
这里有一个库TypePreservingCodingAdapter可以做到这一点(可以安装Cocoapods或SwiftPackageManager)。
下面的代码可以在Swift
4.2
上编译和运行。不幸的是,对于每个子类,您都需要自己实现属性的编码和解码。mnowg1ta7#
编译器仅为直接采用
Codable
协议的类型合成可解码代码,以便您在继承中观察单个类型的解码。但是你可以用
KeyValueCoding
包(https://github.com/ikhvorost/KeyValueCoding)尝试下一种通用方法,这个包提供了对所有属性元数据的访问,并允许动态地获取/设置纯swift类型的任何属性。我们的想法是创建一个基本的Coding
类,它采用KeyValueCoding
并实现对init(from: Decoder)
中所有可用属性的解码:在
decodeTypes
变量中提供所有支持的类型进行解码是很重要的。使用方法: