Ios Swift-如何使JSONDecoder正确解析类层次结构中的日期数组
我有两个类,一个扩展另一个(参见下面的Ios Swift-如何使JSONDecoder正确解析类层次结构中的日期数组,ios,json,swift,swift4,jsondecoder,Ios,Json,Swift,Swift4,Jsondecoder,我有两个类,一个扩展另一个(参见下面的DateDemo和DateDemo2)。 如果我在子对象中有一个[Date],JSONDecoder将无法正确解析它 这是我在iOS上运行的测试类DateDecodeTests。 基本上,我只是尝试了testDateDecodingWithHierarchy测试方法,以通过返回eventsDateTimes3而不是nil 从这两个测试中可以看出,testDateDecoding工作完美,相反,testDateDecodingWithHierarchy在解析e
DateDemo
和DateDemo2
)。
如果我在子对象中有一个[Date]
,JSONDecoder将无法正确解析它
这是我在iOS上运行的测试类DateDecodeTests
。
基本上,我只是尝试了testDateDecodingWithHierarchy
测试方法,以通过返回eventsDateTimes3
而不是nil
从这两个测试中可以看出,testDateDecoding
工作完美,相反,testDateDecodingWithHierarchy
在解析eventsDateTimes3
字段(该字段仅由子类DateDemo2
拥有)时存在问题
DateDemo
符合Decodable
,但没有明确定义init(from:Decoder)抛出。因此,Swift综合了init(from:Decoder)的定义,该定义对DateDemo
的属性进行解码
DateDemo2
继承自DateDemo
。它添加了一个属性:eventsDateTimes3
。它没有定义任何初始值设定项。通常,斯威夫特会抱怨缺少初始值设定人。但是,由于新属性既是var
又是可选的,Swift认为它的默认值为nil
由于DateDemo2
的唯一新属性具有默认值,因此Swift适用。您的DateDemo2
类继承其超类的所有指定初始值设定项。只有一个初始值设定项可继承:合成的可解码的初始值设定项。继承的初始化程序将eventsDateTimes3
初始化为其默认值(nil
)。这就是继承的初始值设定项的工作方式
您希望Swift通过从解码器
初始化事件DateTimes3
,为DateDemo2
合成一个可解码的
初始化器,就像它对DateDemo
所做的那样。但斯威夫特并没有这样做。以下是Itai Ferber(负责编码
实现的苹果程序员)在
如果编译器能够合成SuperClass.init(from:)
而不是继承,那么这种情况将得到改善,但如果没有对Swift的协议一致性和继承系统进行重构(并且没有语法来消除“我不提供实现,因为我想继承”与。“我之所以不提供实现,是因为我想
换句话说,有两种合法的情况:
您希望子类继承其超类的初始值设定项,并默认初始化新属性
您希望编译器合成一个对新属性进行解码的初始值设定项
您现在总是得到#1,因为这是添加可编码系统之前的全部内容,而且没有语法告诉编译器您想要的是#2
因此,您需要在DateDemo2
中自己实现init(from:)
class DateDemo2 : DateDemo {
var eventsDateTimes3 : [Date]?
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
eventsDateTimes3 = try container.decode([Date]?.self, forKey: .eventsDateTimes3)
try super.init(from: decoder)
}
private enum CodingKeys: String, CodingKey {
case eventsDateTimes3
}
}
DateDemo
符合Decodable
,但没有明确定义init(from:Decoder)throws
。因此Swift综合了init(from:Decoder)throws
的定义,该定义对DateDemo
的属性进行解码
DateDemo2
继承自DateDemo
。它添加了一个属性:eventsDateTimes3
。它不定义任何初始值设定项。通常,Swift会抱怨缺少初始值设定项。但是,由于新属性既是var
又是可选的,所以Swift认为它的默认值为nil
由于DateDemo2
的唯一新属性具有默认值,因此Swift适用。您的DateDemo2
类继承其超类的所有指定初始值设定项。只有一个初始值设定项可继承:合成的可解码的
初始值设定项。继承的初始值设定项初始化eventsDateTimes3
to它的默认值(nil
)。这就是继承的初始值设定项的工作方式
您希望Swift通过从解码器
初始化事件DateTimes3
,为DateDemo2
合成一个可解码的
初始化器,就像它为DateDemo2
所做的那样。但Swift没有这样做。下面是它的想法(负责编码
实现的苹果程序员)在
如果编译器能够合成SuperClass.init(from:)
而不是继承,那么这种情况将得到改善,但如果没有对Swift的协议一致性和继承系统进行重构(并且没有语法来消除“我不提供实现,因为我想继承”与我不提供实现,因为我想
换句话说,有两种合法的情况:
您希望子类继承其超类的初始值设定项,并默认初始化新属性
您希望编译器合成一个对新属性进行解码的初始值设定项
您现在总是得到#1,因为这是添加可编码系统之前的全部内容,而且没有语法告诉编译器您想要的是#2
因此,您需要在DateDemo2
中自己实现init(from:)
class DateDemo2 : DateDemo {
var eventsDateTimes3 : [Date]?
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
eventsDateTimes3 = try container.decode([Date]?.self, forKey: .eventsDateTimes3)
try super.init(from: decoder)
}
private enum CodingKeys: String, CodingKey {
case eventsDateTimes3
}
}
这取决于您的用例,但另一个解决方法是将公共属性放在协议中,并使用它代替继承。(还允许您使用structs这取决于您的用例,但另一个解决方法是将公共属性放在协议中,并使用它代替继承。)。(也允许你使用structs是的