UnkeyedEncodingContainer 和 KeyedEncodingContainerProtocol 中的 superEncoder 有何用途?

Amy*_*ose 4 encoding swift

我很抱歉问这样一个基本问题,但我无法在任何地方找到答案:

为了制作一个Encoder,您必须定义不同类型的容器:

  • SingleValueEncodingContainer
  • UnkeyedEncodingContainer
  • KeyedEncodingContainerProtocol是的,命名规范很奇怪

最后两个必须都包含一个名为的方法superEncoder,但是我无法在任何地方找到它应该做什么。这个问题有一个实现它的答案,但没有解释它,本次演讲只是顺便提到了它。

它应该做什么,有什么用?

Ita*_*ber 6

superEncoder在编码器和superDecoder解码器中是一种能够在容器内“保留”嵌套容器的方法,而无需提前知道它将是什么类型。

\n

这样做的主要目的之一是支持Encodable/ Decodableclasses 中的继承:类T: Encodable可以选择将其内容编码为UnkeyedContainer,但其子类U: T可以选择将其内容编码为KeyedContainer

\n

在 中U.encode(to:)U需要调用super.encode(to:), 并传入Encoder\xe2\x80\x94 但它无法传入Encoder它收到的 ,因为它已经以密钥方式对其内容进行了编码,并且请求T未密钥的容器是无效的从那以后Encoder。(一般来说,U甚至不知道T可能需要什么样的容器。)

\n

那么,逃生舱口是为了U向其容器请求嵌套,Encoder以便能够将其传递给其超类。容器将为嵌套值腾出空间,并创建一个新值Encoder,允许写入该保留空间。T然后可以使用嵌套的方式Encoder进行编码。

\n

结果最终看起来就像U请求了一个嵌套容器并将 的值编码T到其中。

\n
\n

为了使这一点更加具体,请考虑以下事项:

\n
import Foundation\n\nclass T: Encodable {\n    let x, y: Int\n    init(x: Int, y: Int) { self.x = x; self.y = y }\n    \n    func encode(to encoder: Encoder) throws {\n        var container = encoder.unkeyedContainer()\n        try container.encode(x)\n        try container.encode(y)\n    }\n}\n\nclass U: T {\n    let z: Int\n    init(x: Int, y: Int, z: Int) { self.z = z; super.init(x: x, y: y) }\n    \n    enum CodingKeys: CodingKey { case z }\n    \n    override func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(z, forKey: .z)\n        \n        /* How to encode T.x and T.y? */\n    }\n}\n\nlet u = U(x: 1, y: 2, z: 3)\nlet data = try JSONEncoder().encode(u)\nprint(String(data: data, encoding: .utf8))\n
Run Code Online (Sandbox Code Playgroud)\n

U有一些关于如何编码x和 的选项y

\n
    \n
  1. 它可以通过在其枚举中T包含x和来真正覆盖编码策略并直接对其进行编码。这忽略了如何编码,如果需要解码,意味着您必须能够创建一个新的而不调用它的yCodingKeysTT init(from:)

    \n
  2. \n
  3. 它可以调用super.encode(to: encoder)将超类编码到与其相同的编码器中。在这种情况下,这将崩溃,因为U已经从 请求了一个带密钥的容器encoder,并且调用T.encode(to:)将立即从同一编码器请求一个未带密钥的容器

    \n
      \n
    • 一般来说,如果两者都请求相同的容器类型,这可能会起作用,实际上不建议依赖它。根据编码方式,它可能会覆盖已经编码的值TUTU
    • \n
    \n
  4. \n
  5. 嵌套在带钥匙的容器T super.encode(to: container.superEncoder());这将在容器字典中保留一个位置,创建一个新的Encoder,并T写入该编码器。JSON 格式的结果将是:

    \n
    { "z": 3,\n  "super": [1, 2] }\n
    Run Code Online (Sandbox Code Playgroud)\n
  6. \n
\n