You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 19:15:01