Swift-如何使JSONDecoder正确解析类层次结构中的Date数组

时间:2018-10-18 18:18:14

标签: ios json swift swift4 jsondecoder

我有两个类,一个类扩展了另一个类(请参见下面的DateDemoDateDemo2)。 如果孩子中有[Date],则JSONDecoder无法正确解析它。

这是我在iOS上运行的测试类DateDecodeTests。 基本上,我只是尝试使用testDateDecodingWithHierarchy测试方法以通过返回不同于eventsDateTimes3的{​​{1}}。

从这两个测试中可以看出,nil的工作原理完美而相反,testDateDecoding在解析testDateDecodingWithHierarchy字段(该字段仅由子类{ {1}}。

eventsDateTimes3

2 个答案:

答案 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. 您希望子类继承其超类的初始化程序,并默认初始化新属性。
  2. 您希望编译器合成一个可初始化新属性的初始化程序。

您现在总是获得#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])