我很抱歉问这样一个基本问题,但我无法在任何地方找到答案:
为了制作一个Encoder
,您必须定义不同类型的容器:
SingleValueEncodingContainer
UnkeyedEncodingContainer
KeyedEncodingContainerProtocol
(是的,命名规范很奇怪)最后两个必须都包含一个名为的方法superEncoder
,但是我无法在任何地方找到它应该做什么。这个问题有一个实现它的答案,但没有解释它,本次演讲只是顺便提到了它。
它应该做什么,有什么用?
superEncoder
在编码器和superDecoder
解码器中是一种能够在容器内“保留”嵌套容器的方法,而无需提前知道它将是什么类型。
这样做的主要目的之一是支持Encodable
/ Decodable
classes 中的继承:类T: Encodable
可以选择将其内容编码为UnkeyedContainer
,但其子类U: T
可以选择将其内容编码为KeyedContainer
。
在 中U.encode(to:)
,U
需要调用super.encode(to:)
, 并传入Encoder
\xe2\x80\x94 但它无法传入Encoder
它收到的 ,因为它已经以密钥方式对其内容进行了编码,并且请求T
未密钥的容器是无效的从那以后Encoder
。(一般来说,U
甚至不知道T
可能需要什么样的容器。)
那么,逃生舱口是为了U
向其容器请求嵌套,Encoder
以便能够将其传递给其超类。容器将为嵌套值腾出空间,并创建一个新值Encoder
,允许写入该保留空间。T
然后可以使用嵌套的方式Encoder
进行编码。
结果最终看起来就像U
请求了一个嵌套容器并将 的值编码T
到其中。
为了使这一点更加具体,请考虑以下事项:
\nimport 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)\nU
有一些关于如何编码x
和 的选项y
:
它可以通过在其枚举中T
包含x
和来真正覆盖编码策略并直接对其进行编码。这忽略了如何编码,如果需要解码,意味着您必须能够创建一个新的而不调用它的y
CodingKeys
T
T
init(from:)
它可以调用super.encode(to: encoder)
将超类编码到与其相同的编码器中。在这种情况下,这将崩溃,因为U
已经从 请求了一个带密钥的容器encoder
,并且调用T.encode(to:)
将立即从同一编码器请求一个未带密钥的容器
T
U
T
U
嵌套在带钥匙的容器T
内super.encode(to: container.superEncoder())
;这将在容器字典中保留一个位置,创建一个新的Encoder
,并T
写入该编码器。JSON 格式的结果将是:
{ "z": 3,\n "super": [1, 2] }\n
Run Code Online (Sandbox Code Playgroud)\n 归档时间: |
|
查看次数: |
683 次 |
最近记录: |