我有两个类,一个类扩展了另一个类(请参见下面的DateDemo
和DateDemo2
)。
如果孩子中有[Date]
,则JSONDecoder无法正确解析它。
这是我在iOS上运行的测试类DateDecodeTests
。
基本上,我只是尝试使用testDateDecodingWithHierarchy
测试方法以通过返回不同于eventsDateTimes3
的{{1}}。
从这两个测试中可以看出,nil
的工作原理完美而相反,testDateDecoding
在解析testDateDecodingWithHierarchy
字段(该字段仅由子类{ {1}}。
eventsDateTimes3
答案 0 :(得分:4)
DateDemo
符合Decodable
,但未明确定义init(from:Decoder) throws
。因此,Swift合成了init(from:Decoder) throws
的定义,该定义对DateDemo
的属性进行了解码。
DateDemo2
继承自DateDemo
。它添加了一个属性:eventsDateTimes3
。它没有定义任何初始化程序。通常,Swift会抱怨缺少初始化器。但是,由于新属性既是var
也是可选属性,因此Swift认为它的默认值为nil
。
由于DateDemo2
的唯一新属性具有默认值,因此Swift将应用automatic initializer inheritance。您的DateDemo2
类继承了其超类的所有指定初始化器。只能继承一个初始化程序:合成的Decodable
初始化程序。继承的初始化程序将eventsDateTimes3
初始化为其默认值(nil
)。继承的初始化程序就是这样工作的。
您希望Swift通过为Decodable
初始化DateDemo2
来为DateDemo
合成eventsDateTimes3
的{{1}}初始化器。但是Swift并没有这样做。以下是Itai Ferber(负责Decoder
实现的Apple程序员)在Swift forum上说的话:
如果编译器可以合成
Coding
而不是继承,这种情况将得到改善,但是如果没有重构Swift的协议一致性和继承系统(并且没有消除“ I”之间语法的歧义),它将无法解决。我没有提供实现,因为我想继承” vs.“我没有提供实现,因为我想合成”)
换句话说,有两种合法情况:
您现在总是获得#1,因为这就是添加SuperClass.init(from:)
系统之前的全部,并且因为没有语法告诉编译器您想要#2。
因此,您需要自己在Codable
中实现init(from:)
。这是一个实现:
DateDemo2
答案 1 :(得分:1)
这取决于您的用例,但是另一种解决方法是将通用属性放入协议中,并使用它代替继承。 (还允许您使用structs)
protocol AnyDateHolder: Decodable {
var dates : [Date] {get set}
var eventsDateTimes : [Date]? {get set}
var eventsDateTimes2 : [Date]? {get set}
}
class DateDemo: AnyDateHolder {
var dates : [Date]
var eventsDateTimes : [Date]?
var eventsDateTimes2 : [Date]?
}
class DateDemo2: AnyDateHolder {
var dates : [Date]
var eventsDateTimes : [Date]?
var eventsDateTimes2 : [Date]?
var eventsDateTimes3 : [Date]?
}
第二次测试时,它会打印:
[2018-10-17 22:00:00 +0000, 2018-10-17 23:30:00 +0000]
Optional([2018-10-18 20:00:00 +0000, 2018-10-30 23:30:00 +0000, 2018-11-08 19:00:00 +0000])
Optional([])
Optional([2018-10-18 20:00:00 +0000, 2018-10-30 23:30:00 +0000, 2018-11-08 19:00:00 +0000])