很抱歉问了这么一个基本的问题,但我在任何地方都找不到答案:

要制作Encoder,必须定义不同类型的容器:

  • SingleValueEncodingContainer
  • UnkeyedEncodingContainer
  • KeyedEncodingContainerProtocol (yes the naming spec is weird)

最后两个必须都包含一个名为superEncoder的方法,但我一直无法找到它应该在任何地方执行的操作.This question有一个实现它的答案,但没有解释它,而this talk只是顺便提到它.

它应该做什么,为什么?

推荐答案

superEncoder英寸编码器和superDecoder英寸解码器是一种能够"保留"容器内部嵌套容器的方法,而不需要提前知道它将是什么类型.

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

U.encode(to:)中,U需要调用super.encode(to:),并传入一个Encoder,但它不能传入它接收到的Encoder,因为它已经用密钥方式对其内容进行了编码,而TEncoder请求一个未加密的容器是无效的.(一般来说,U甚至不知道T想要什么样的容器.)

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

结果看起来好像U请求了一个嵌套容器,并将T的值编码到其中.


为了使这一点更具体,请考虑以下内容:

import Foundation

class T: Encodable {
    let x, y: Int
    init(x: Int, y: Int) { self.x = x; self.y = y }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        try container.encode(x)
        try container.encode(y)
    }
}

class U: T {
    let z: Int
    init(x: Int, y: Int, z: Int) { self.z = z; super.init(x: x, y: y) }
    
    enum CodingKeys: CodingKey { case z }
    
    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(z, forKey: .z)
        
        /* How to encode T.x and T.y? */
    }
}

let u = U(x: 1, y: 2, z: 3)
let data = try JSONEncoder().encode(u)
print(String(data: data, encoding: .utf8))

U有几个选项可以 Select 如何对xy进行编码:

  1. 它可以在CodingKeys枚举中包含xy,并直接对它们进行编码,从而真正覆盖T的编码策略.这忽略了T希望编码的方式,如果需要decoding,则意味着您必须能够创建一个调用其init(from:)的新T without

  2. 它可以调用super.encode(to: encoder)将超类编码到same编码器中.在这种情况下,这将是crash,因为U已经从encoder请求密钥容器,而调用T.encode(to:)将立即从同一编码器请求未密钥容器

    • 一般来说,如果TU都请求相同的容器类型,那么may就可以工作,但不建议依赖它.根据T的编码方式,它可能会覆盖U已经编码的值
  3. super.encode(to: container.superEncoder())嵌套T inside个键控容器;这将在容器字典中保留一个位置,创建一个新的Encoder,并对该编码器进行T次写入.在JSON中,这样做的结果将是:

    { "z": 3,
      "super": [1, 2] }
    

Swift相关问答推荐

计算Vision OS相机与Vision OS中3D模型之间的距离

启用完成并发判断以及如何解决警告(续)

如何在realityKit中反转USDZ动画

避免嵌套导航TabView

如何把多个可观测性变成一个完备性?

并发访问SWIFT中数组的非重叠子范围

为什么 Swift URL 的 init?(string: String,relativeTo: URL?) 仅添加协议?

在SwiftUI中使用ForEach循环来显示字典项的键和值在Form视图中

当变量首次用于其自己的初始化时,如何清除变量...在初始化之前使用错误?

如何在 swiftui 中设置给定字符串类型日期的日期倒计时?

SwiftUI:按钮的圆形边缘的边框尺寸加倍

与 SwiftUI 中的 onChange 修饰符相比,objectWillChangeSequence 的目的是什么?

为什么更改属性后动画会加速? SwiftUI

为什么 `map(foo)` 和 `map{ foo($0) }` 返回不同的结果?

在视图中设置所有变量

如何防止 UITableViewCell 移动(Swift 5)

subscribeOn 和 observeOn 的顺序重要吗?

根据禁用与否更改 SwiftUI 中按钮的 colored颜色

如何使用 Swift 将文本文件逐行加载到数组中?

无法将 NSAttributedString.DocumentAttributeKey 类型的值转换为 .DocumentReadingOptionKey