Swift JSONDecoder 解码缺失key时如何自动使用结构体预设默认值
实现方案
推荐使用属性包装器方案,全程不需要编写任何自定义解码逻辑,仅需给需要保留默认值的属性添加标记即可,侵入性极低,无冗余代码。
步骤1:定义属性包装器与解码扩展
@propertyWrapper struct Default<T: Codable>: Codable { var wrappedValue: T init(wrappedValue: T) { self.wrappedValue = wrappedValue } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() wrappedValue = try container.decode(T.self) } } extension KeyedDecodingContainer { func decode<T>(_ type: Default<T>.Type, forKey key: Key) throws -> Default<T> { // 存在对应key且类型匹配则返回解码结果,否则返回属性声明时的默认值 if let value = try? decodeIfPresent(type, forKey: key) { return value } return Default(wrappedValue: (try! T(from: EmptyDecoder()))) } } // 辅助空解码器实现,用于读取默认值 fileprivate struct EmptyDecoder: Decoder { var codingPath: [CodingKey] = [] var userInfo: [CodingUserInfoKey : Any] = [:] func container<Key>(keyedBy type: Key.Type) throws -> KeyedDecodingContainer<Key> where Key : CodingKey { throw DecodingError.valueNotFound(Any.self, .init(codingPath: [], debugDescription: "")) } func unkeyedContainer() throws -> UnkeyedDecodingContainer { throw DecodingError.valueNotFound(Any.self, .init(codingPath: [], debugDescription: "")) } func singleValueContainer() throws -> SingleValueDecodingContainer { throw DecodingError.valueNotFound(Any.self, .init(codingPath: [], debugDescription: "")) } }
步骤2:修改配置结构体
仅需给所有需要保留默认值的属性添加@Default标记即可,原有默认值定义无需修改:
struct DefaultConfiguration : Codable { @Default var version = 1 @Default var includedB = "2" @Default var notIncludedC = "3" }
步骤3:测试解码效果
使用你给出的测试JSON解码时,不会触发解码失败错误,notIncludedC会自动保留你预设的默认值"3":
let testJSON = """ {"version":1,"includedB":"B","___notIncludedC":"C"} """ let decoder = JSONDecoder() if let data = testJSON.data(using: .utf8), let config = try? decoder.decode(DefaultConfiguration.self, from: data) { print(config.notIncludedC) // 输出 3 }
方案优势
- 无冗余代码:无需为每个结构体编写自定义解码方法,新增属性仅需添加标记即可
- 低侵入:原有业务逻辑不需要做任何修改,默认值完全遵循你预设的数值
- 兼容Codable原生特性兼容:支持嵌套结构体、自定义解码策略等所有原生能力
内容的提问来源于stack exchange,提问作者user2161301
相关产品推荐
相关产品推荐

