
我正在尝试实现一个与Codable使用CodingKeys枚举类似功能的协议。
使用Codable和CodingKeys,如果你没有在CodingKeys枚举中为Codable对象的每个属性实现一个案例,它会导致编译器错误,指出该对象不符合协议。
我查看了文档,我唯一能找到与Codable(Encodable和Decodable)协议有关的东西是实现func encode(to encoder: Encoder)和init(from decoder: Decoder)函数的要求。
我得到的最接近的是如下定义协议:
protocol TestProtocol {
    associatedType Keys: CodingKey
}
这要求实现者具有符合Keys的CodingKey属性,但它不强制要求所有属性都有一个案例。此外,您不能像使用Keys一样将Codable属性声明为私有属性。
Codable和CodingKeys的处理程度是否高于通过API公开的程度?
如果没有,有没有办法在CodingKeys之外实现Codable功能?
投票
你问两个问题。我会不按时回答。
Codable和CodingKeys的处理范围是否比通过API公开的更深层次?
是的,Swift编译器知道Encodable,Decodable和CodingKey协议,并为它们提供特殊代码。
如果符合某些条件,编译器可以合成一个名为CodingKey的enum兼容的CodingKeys,init(from:)初始化器和encode(to:)方法。条件在SE-0166中详细说明:
符合
Encodable和Decodable要求也可以自动合成某些类型:Encodable的类型,其属性都是Encodable,获得自动生成的String支持的CodingKeyenum映射属性到案例名称。类似地,Decodable类型的属性都是Decodable落入(1)的类型 - 以及手动提供CodingKeyenum(直接命名为CodingKeys,或通过typealias)的类型,其案例按名称将1对1映射到Encodable/Decodable属性 - 自动合成init(from:)和encode(to:)as适当的,使用这些属性和键 既不属于(1)也不属于(2)的类型必须提供自定义密钥类型(如果需要)并提供自己的init(from:)和encode(to:),视情况而定
请注意,除非依赖于编译器合成的一致性,否则CodingKey兼容类型通常不必命名为CodingKeys或甚至是enum。
此外,请注意,如果依靠编译器合成CodingKeys或CodingKey,符合init(from:)的encode(to:)类型只需要为其封闭类型的每个成员都有一个案例。
如果你手动实现init(from:)和encode(to:),你可以使用任何名称为你的CodingKey兼容类型,它只需要你关心的案例。如果您只使用单值容器或无键容器进行存储,则甚至不需要符合CodingKey的类型。
如果没有,有没有办法在Codable之外实现CodingKeys功能?
如果“功能”是指编译器自动合成实现的方式,那么唯一的方法是使用代码生成器(如Sourcery或gyb)生成源代码并将其提供给编译器。
如果,通过“功能”,你的意思是编译器需要封闭类型的每个Encodable / Decodable成员的密钥成员的方式,那么唯一的方法是运行一个单独的程序来分析你的源代码和错误,如果有任何情况是失踪。你不能让标准的Swift编译器为你做这件事。
 
                