简体   繁体   English

Codable 和 CodingKeys

[英]Codable and CodingKeys

I'm trying to implement a protocol with similar functionality to how Codable uses the CodingKeys enum.我正在尝试实现一个与Codable如何使用CodingKeys枚举具有类似功能的协议。

With Codable and CodingKeys , if you don't implement a case in the CodingKeys enum for every property on the Codable object, it causes a compiler error stating that the object does not conform to the protocol.使用CodableCodingKeys ,如果您没有在CodingKeys枚举中为Codable对象上的每个属性实现 case,则会导致编译器错误,指出该对象不符合协议。

I have looked through documentation, and the only thing I can find related to the Codable ( Encodable and Decodable ) protocol is the requirement to implement the func encode(to encoder: Encoder) and init(from decoder: Decoder) functions.我查看了文档,唯一能找到的与Codable ( Encodable and Decodable ) 协议相关的是实现func encode(to encoder: Encoder)init(from decoder: Decoder)函数的要求。

The closest I've gotten is defining a protocol as follows:我得到的最接近的是定义如下协议:

protocol TestProtocol {
    associatedType Keys: CodingKey
}

This requires the implementer to have a Keys property that conforms to CodingKey , but it does not enforce the requirement to have a case for all properties.这要求实现者有一个符合CodingKeyKeys属性,但它并不强制要求所有属性都有一个案例。 Additionally, you cannot declare the Keys property as private like you can with Codable .此外,您不能像使用Codable一样将Keys属性声明为私有。

Are Codable and CodingKeys handled at a deeper level than what is exposed through the APIs? CodableCodingKeys处理的层次是否比通过 API 公开的更深?

If not, is there a way to implement the CodingKeys functionality outside of Codable ?如果没有,有没有办法在Codable之外实现CodingKeys功能?

You ask two questions.你问两个问题。 I think it will be easier to explain them in reverse order.我认为以相反的顺序解释它们会更容易。

Are Codable and CodingKeys are handled at a deeper level than what is exposed through the APIs? Codable 和 CodingKeys 的处理层次是否比通过 API 公开的更深?

Yes, the Swift compiler knows about the Encodable , Decodable , and CodingKey protocols and has special code for them.是的,Swift 编译器知道EncodableDecodableCodingKey协议,并为它们提供了特殊的代码。

The compiler can synthesize a CodingKey -compliant enum named CodingKeys , the init(from:) initializer, and the encode(to:) method, if some conditions are met.如果满足某些条件,编译器可以合成一个名为CodingKeysCodingKeyenuminit(from:)初始化程序和encode(to:)方法。 The conditions are spelled out in SE-0166 : SE-0166中详细说明了这些条件:

Encodable & Decodable requirements can be automatically synthesized for certain types as well:也可以为某些类型自动合成可Encodable和可Decodable要求:

  1. Types conforming to Encodable whose properties are all Encodable get an automatically generated String -backed CodingKey enum mapping properties to case names.符合Encodable其属性都是Encodable的类型会自动生成String支持的CodingKey enum映射属性到案例名称。 Similarly for Decodable types whose properties are all Decodable类似地,对于其属性都是DecodableDecodable类型
  2. Types falling into (1) — and types which manually provide a CodingKey enum (named CodingKeys , directly, or via a typealias ) whose cases map 1-to-1 to Encodable / Decodable properties by name — get automatic synthesis of init(from:) and encode(to:) as appropriate, using those properties and keys属于 (1) 的类型——以及手动提供CodingKey enum (直接命名为CodingKeys或通过typealias命名)的类型,其情况按名称一对一映射到Encodable / Decodable属性——自动合成init(from:)encode(to:)酌情使用这些属性和键
  3. Types which fall into neither (1) nor (2) will have to provide a custom key type if needed and provide their own init(from:) and encode(to:) , as appropriate如果需要,既不属于 (1) 也不属于 (2) 的类型必须提供自定义键类型,并酌情提供它们自己的init(from:)encode(to:)

Note that the CodingKey -compliant type does not in general have to be named CodingKeys or even be an enum unless you are relying on compiler-synthesized conformance.请注意,与CodingKey兼容的类型通常不必命名为CodingKeys甚至是enum ,除非您依赖编译器综合的一致性。

Furthermore, note that a CodingKeys type conforming to CodingKey only needs to have a case for every member of its enclosing type if you are relying on the compiler to synthesize init(from:) or encode(to:) .此外,请注意,如果您依赖编译器来合成init(from:)encode(to:) ,则符合CodingKeyCodingKeys类型只需要为其封闭类型的每个成员都有一个案例。

If you're manually implementing init(from:) and encode(to:) , you can use any name for your CodingKey -compliant type, and it only has to have the cases you care about.如果您手动实现init(from:)encode(to:) ,您可以为CodingKey的类型使用任何名称,并且它只需要包含您关心的情况。 You don't even need a CodingKey -compliant type if you're only using a single-value container or an unkeyed container for storage.如果您仅使用单值容器或无键容器进行存储,您甚至不需要CodingKey的类型。

If not, is there a way to implement the CodingKeys functionality outside of Codable?如果没有,有没有办法在 Codable 之外实现 CodingKeys 功能?

If, by “functionality”, you mean the way the compiler automatically synthesizes implementations, then the only way is by using a code generator (like Sourcery or gyb) to generate source code and feed it to the compiler.如果“功能”是指编译器自动合成实现的方式,那么唯一的方法是使用代码生成器(如 Sourcery 或 gyb)生成源代码并将其提供给编译器。

If, by “functionality”, you mean the way the compiler requires a key member for each Encodable / Decodable member of the enclosing type, then the only way is by running a separate program that analyzes your source code and errors out if any case is missing.如果“功能”是指编译器需要为封闭类型的每个Encodable / Decodable成员提供一个关键成员的方式,那么唯一的方法是运行一个单独的程序来分析您的源代码并在任何情况下排除错误失踪。 You can't make the standard Swift compiler do it for you.你不能让标准的 Swift 编译器为你做这件事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM