Codable和CodingKeys

我正在尝试实现一个与Codable使用CodingKeys枚举类似功能的协议。

使用CodableCodingKeys,如果你没有在CodingKeys枚举中为Codable对象的每个属性实现一个案例,它会导致编译器错误,指出该对象不符合协议。

我查看了文档,我唯一能找到与CodableEncodableDecodable)协议有关的东西是实现func encode(to encoder: Encoder)init(from decoder: Decoder)函数的要求。

我得到的最接近的是如下定义协议:

protocol TestProtocol {
    associatedType Keys: CodingKey
}

这要求实现者具有符合KeysCodingKey属性,但它不强制要求所有属性都有一个案例。此外,您不能像使用Keys一样将Codable属性声明为私有属性。

CodableCodingKeys的处理程度是否高于通过API公开的程度?

如果没有,有没有办法在CodingKeys之外实现Codable功能?

2
投票

你问两个问题。我会不按时回答。

Codable和CodingKeys的处理范围是否比通过API公开的更深层次?

是的,Swift编译器知道EncodableDecodableCodingKey协议,并为它们提供特殊代码。

如果符合某些条件,编译器可以合成一个名为CodingKeyenum兼容的CodingKeysinit(from:)初始化器和encode(to:)方法。条件在SE-0166中详细说明:

EncodableDecodable要求也可以自动合成某些类型:

符合 Encodable的类型,其属性都是 Encodable,获得自动生成的 String支持的 CodingKey enum映射属性到案例名称。类似地, Decodable类型的属性都是 Decodable 落入(1)的类型 - 以及手动提供 CodingKey enum(直接命名为 CodingKeys,或通过 typealias)的类型,其案例按名称将1对1映射到 Encodable / Decodable属性 - 自动合成 init(from:)encode(to:) as适当的,使用这些属性和键 既不属于(1)也不属于(2)的类型必须提供自定义密钥类型(如果需要)并提供自己的 init(from:)encode(to:),视情况而定

请注意,除非依赖于编译器合成的一致性,否则CodingKey兼容类型通常不必命名为CodingKeys或甚至是enum

此外,请注意,如果依靠编译器合成CodingKeysCodingKey,符合init(from:)encode(to:)类型只需要为其封闭类型的每个成员都有一个案例。

如果你手动实现init(from:)encode(to:),你可以使用任何名称为你的CodingKey兼容类型,它只需要你关心的案例。如果您只使用单值容器或无键容器进行存储,则甚至不需要符合CodingKey的类型。

如果没有,有没有办法在Codable之外实现CodingKeys功能?

如果“功能”是指编译器自动合成实现的方式,那么唯一的方法是使用代码生成器(如Sourcery或gyb)生成源代码并将其提供给编译器。

如果,通过“功能”,你的意思是编译器需要封闭类型的每个Encodable / Decodable成员的密钥成员的方式,那么唯一的方法是运行一个单独的程序来分析你的源代码和错误,如果有任何情况是失踪。你不能让标准的Swift编译器为你做这件事。