Swift Encodable如何将nil属性编码为空JSON对象
解决方案
Swift 内置的 JSONEncoder 对可选值的默认编码策略是:如果可选值为 nil,会自动忽略对应的键,不会写入最终的JSON结构中,这就是你当前代码不会输出bar字段的原因。
要实现nil编码为空JSON对象{}的需求,可以用下面两种方案:
方案1:手动实现Encodable协议
重写Foo的encode方法,单独处理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) if let bar = bar { try container.encode(bar, forKey: .bar) } else { // nil时编码为空字典,对应JSON空对象结构 try container.encode([String: Any](), forKey: .bar) } } } struct Bar: Encodable { let number: Int } // 测试代码 let data = try! JSONEncoder().encode(Foo()) print(String(data: data, encoding: .utf8)!) // 输出:{"id":10,"bar":{}}
方案2:属性包装器通用处理
如果项目中有大量类似需求,可以定义属性包装器复用逻辑,不用每个结构体都手写编码方法:
// 定义通用属性包装器 @propertyWrapper struct EncodeNilAsEmptyObject<T: Encodable>: Encodable { var wrappedValue: T? init(wrappedValue: T?) { self.wrappedValue = wrappedValue } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() if let value = wrappedValue { try container.encode(value) } else { try container.encode([String: String]()) } } } // 业务层直接使用标记即可 struct Foo: Encodable { let id = 10 @EncodeNilAsEmptyObject let bar: Bar? = nil } struct Bar: Encodable { let number: Int }
注意:如果同时需要支持
Decodable能力,还需要对应实现空对象解码为nil的逻辑,仅编码场景以上代码可以直接使用。
内容的提问来源于stack exchange,提问作者Silis Alin
相关产品推荐
相关产品推荐

