Swift 可编码:将 nil 编码为空对象
Swift Encodable: encode nil as an empty object
如何将 nil 属性 编码为空 JSON 对象?
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
}
struct Bar: Encodable {
let number: Int
}
let data = try! JSONEncoder().encode(Foo())
print(String(data: data, encoding: .utf8)!)
打印出来:
"{"id":7}"
我想要的是:
"{"id":7, "bar":{}}"
当 bar = nil
时,您可以向 encoder
引入一个没有属性的空结构
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
enum CodingKeys : String, CodingKey {
case id
case bar
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
if let bar = bar {
try container.encode(bar, forKey: .bar)
}
else {
try container.encode(Empty(), forKey: .bar)
}
}
}
struct Bar: Encodable {
let number: Int
}
struct Empty: Encodable {
}
为 Foo
实现自定义 encode(to:)
,如果 Bar
为 nil
,则使用空字典
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
enum CodingKeys: String, CodingKey {
case id, bar
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
switch bar {
case .some(let value):
try container.encode(value, forKey: .bar)
case .none:
try container.encode([String: Bar?](), forKey: .bar)
}
}
}
不确定您为什么需要这个,因为编码为解码失败的形式通常不是这样。
尽管如此,如果您发现自己在多个地方需要这种逻辑,您可以使用这种功能扩展 KeyedEncodingContainer
:
extension KeyedEncodingContainer {
mutating func encodeOptional<T: Encodable>(_ value: T?, forKey key: Self.Key) throws {
if let value = value { try encode(value, forKey: key) }
else { try encode([String:String](), forKey: key) }
}
}
,然后在Foo
中实现encode(to:)
方法:
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
enum CodingKeys: String, CodingKey {
case id
case bar
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeOptional(bar, forKey: .bar)
}
}
如果您发现自己需要为其他类型的 nil 值编码空 JSON 对象,您还可以使用类似的 encodeOptional
方法扩展 UnkeyedDecodingContainer
和 SingleValueDecodingContainer
容器数量。
如何将 nil 属性 编码为空 JSON 对象?
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
}
struct Bar: Encodable {
let number: Int
}
let data = try! JSONEncoder().encode(Foo())
print(String(data: data, encoding: .utf8)!)
打印出来:
"{"id":7}"
我想要的是:
"{"id":7, "bar":{}}"
当 bar = nil
encoder
引入一个没有属性的空结构
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
enum CodingKeys : String, CodingKey {
case id
case bar
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
if let bar = bar {
try container.encode(bar, forKey: .bar)
}
else {
try container.encode(Empty(), forKey: .bar)
}
}
}
struct Bar: Encodable {
let number: Int
}
struct Empty: Encodable {
}
为 Foo
实现自定义 encode(to:)
,如果 Bar
为 nil
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
enum CodingKeys: String, CodingKey {
case id, bar
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
switch bar {
case .some(let value):
try container.encode(value, forKey: .bar)
case .none:
try container.encode([String: Bar?](), forKey: .bar)
}
}
}
不确定您为什么需要这个,因为编码为解码失败的形式通常不是这样。
尽管如此,如果您发现自己在多个地方需要这种逻辑,您可以使用这种功能扩展 KeyedEncodingContainer
:
extension KeyedEncodingContainer {
mutating func encodeOptional<T: Encodable>(_ value: T?, forKey key: Self.Key) throws {
if let value = value { try encode(value, forKey: key) }
else { try encode([String:String](), forKey: key) }
}
}
,然后在Foo
中实现encode(to:)
方法:
struct Foo: Encodable {
let id = 10
let bar: Bar? = nil
enum CodingKeys: String, CodingKey {
case id
case bar
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encodeOptional(bar, forKey: .bar)
}
}
如果您发现自己需要为其他类型的 nil 值编码空 JSON 对象,您还可以使用类似的 encodeOptional
方法扩展 UnkeyedDecodingContainer
和 SingleValueDecodingContainer
容器数量。