UnkeyedEncodingContainer 和 KeyedEncodingContainerProtocol 中的 superEncoder 有什么用?
What is superEncoder for in UnkeyedEncodingContainer and KeyedEncodingContainerProtocol?
很抱歉问这样一个基本问题,但我找不到任何地方的答案:
为了制作Encoder
,您必须定义不同类型的容器:
SingleValueEncodingContainer
UnkeyedEncodingContainer
KeyedEncodingContainerProtocol
(是的,命名规范很奇怪)
最后两个必须都包含一个名为 superEncoder
的方法,但是我无法在任何地方找到它应该做什么。 has an answer that implements it but doesn't explain it, and this talk只是顺便提一下。
它应该做什么,有什么用?
编码器中的 superEncoder
和解码器中的 superDecoder
是一种能够在容器内“保留”嵌套容器的方法,而无需提前知道它将是什么类型。
这样做的主要目的之一是支持 Encodable
/Decodable
classes 中的继承:class T: Encodable
可以选择编码它的内容变成一个 UnkeyedContainer
,但是它的子 class U: T
可以选择将它的内容编码成一个 KeyedContainer
.
在 U.encode(to:)
中,U
将需要调用 super.encode(to:)
,并传入一个 Encoder
— 但它不能传入 Encoder
它已收到,因为它已经以密钥方式对其内容进行了编码,并且 T
从 Encoder
请求未密钥的容器是无效的。 (一般来说,U
甚至不知道 T
想要什么样的容器。)
然后,逃生舱口是 U
向其容器请求嵌套的 Encoder
以便能够将其传递给其超级class。容器将为嵌套值创建 space,并创建一个新的 Encoder
,允许写入保留的 space。 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
有一些关于如何编码 x
和 y
:
的选项
它可以通过在其 CodingKeys
枚举中包含 x
和 y
并直接对它们进行编码,从而真正覆盖 T
的编码策略。这忽略了 T
更喜欢编码的方式,如果需要 解码 ,则意味着您必须能够创建一个新的 T
没有调用它的init(from:)
它可以调用 super.encode(to: encoder)
让超级class 编码到它所做的 same 编码器。在这种情况下,这将 崩溃 ,因为 U
已经从 encoder
请求了一个带密钥的容器,而调用 T.encode(to:)
将立即请求一个未带密钥的容器来自同一个编码器
- 一般来说,如果
T
和U
都请求相同的容器类型,这个可能有效,但是真的不建议依赖。根据 T
的编码方式,它可能会覆盖 U
已经编码的值
嵌套 T
inside super.encode(to: container.superEncoder())
;这将在容器字典中保留一个位置,创建一个新的 Encoder
,并让 T
写入该编码器。 JSON 中的结果将是:
{ "z": 3,
"super": [1, 2] }
很抱歉问这样一个基本问题,但我找不到任何地方的答案:
为了制作Encoder
,您必须定义不同类型的容器:
SingleValueEncodingContainer
UnkeyedEncodingContainer
KeyedEncodingContainerProtocol
(是的,命名规范很奇怪)
最后两个必须都包含一个名为 superEncoder
的方法,但是我无法在任何地方找到它应该做什么。
它应该做什么,有什么用?
superEncoder
和解码器中的 superDecoder
是一种能够在容器内“保留”嵌套容器的方法,而无需提前知道它将是什么类型。
这样做的主要目的之一是支持 Encodable
/Decodable
classes 中的继承:class T: Encodable
可以选择编码它的内容变成一个 UnkeyedContainer
,但是它的子 class U: T
可以选择将它的内容编码成一个 KeyedContainer
.
在 U.encode(to:)
中,U
将需要调用 super.encode(to:)
,并传入一个 Encoder
— 但它不能传入 Encoder
它已收到,因为它已经以密钥方式对其内容进行了编码,并且 T
从 Encoder
请求未密钥的容器是无效的。 (一般来说,U
甚至不知道 T
想要什么样的容器。)
然后,逃生舱口是 U
向其容器请求嵌套的 Encoder
以便能够将其传递给其超级class。容器将为嵌套值创建 space,并创建一个新的 Encoder
,允许写入保留的 space。 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
有一些关于如何编码 x
和 y
:
它可以通过在其
CodingKeys
枚举中包含x
和y
并直接对它们进行编码,从而真正覆盖T
的编码策略。这忽略了T
更喜欢编码的方式,如果需要 解码 ,则意味着您必须能够创建一个新的T
没有调用它的init(from:)
它可以调用
super.encode(to: encoder)
让超级class 编码到它所做的 same 编码器。在这种情况下,这将 崩溃 ,因为U
已经从encoder
请求了一个带密钥的容器,而调用T.encode(to:)
将立即请求一个未带密钥的容器来自同一个编码器- 一般来说,如果
T
和U
都请求相同的容器类型,这个可能有效,但是真的不建议依赖。根据T
的编码方式,它可能会覆盖U
已经编码的值
- 一般来说,如果
嵌套
T
insidesuper.encode(to: container.superEncoder())
;这将在容器字典中保留一个位置,创建一个新的Encoder
,并让T
写入该编码器。 JSON 中的结果将是:{ "z": 3, "super": [1, 2] }