Swift encoable:将nil编码为空对象



如何将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方法扩展UnkeyedDecodingContainerSingleValueDecodingContainer

相关内容

  • 没有找到相关文章

最新更新