如何将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":{}}"
可以给encoder
引入一个没有属性的空结构体,当bar = nil
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
。