Swift中如何解码JSON至结构体时忽略双方非共有的字段?
问题场景
将以下JSON解码到Device结构体时出现异常:
错误JSON(注意语法问题:Model行末尾缺少逗号):
{ "SerialNumber": "123", "Model": "iPhone14" "Brand": "Apple" }
原始Swift结构体:
struct Device : Codable, Identifiable { var id = UUID().uuidString let SerialNumber : String let Model : String let Brand : String }
最初的解决方法是手动添加CodingKeys枚举,指定要解码的字段(因为id不存在于JSON中):
private enum CodingKeys: String, CodingKey { case SerialNumber, Model, Brand }
但这种方式有明显弊端:后端移除某个JSON字段时,必须同步修改CodingKeys;同时也不确定如何处理JSON包含结构体没有的额外字段的情况。核心需求是:能否让Codable自动仅解码JSON与结构体共有的字段,无需手动维护CodingKeys?
解决方案
1. 先修正JSON语法错误
首先要解决原始JSON的语法问题:"Model": "iPhone14"行末尾缺少逗号,这是导致解码失败的直接原因之一,修正后的JSON应为:
{ "SerialNumber": "123", "Model": "iPhone14", "Brand": "Apple" }
2. 自动忽略JSON中的额外字段
Swift的Codable默认行为就是自动忽略JSON中结构体没有的字段,无需任何额外配置。比如如果JSON新增了"Color": "Red"字段,解码到Device结构体时会直接跳过该字段,不会引发异常。
3. 允许JSON缺失结构体字段(无需修改CodingKeys)
如果后端可能移除某个字段,只需将结构体中对应的字段改为可选类型,或者给字段设置默认值,这样即使JSON中没有该字段,解码也能成功:
方式一:使用可选类型
struct Device: Codable, Identifiable { var id = UUID().uuidString let serialNumber: String? let model: String? let brand: String? }
注:这里遵循Swift命名规范用小驼峰,配合
JSONDecoder的keyDecodingStrategy自动映射JSON的大驼峰字段:let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromPascalCase let device = try decoder.decode(Device.self, from: jsonData)
方式二:给字段设置默认值
如果不希望用可选类型,可以给字段设置默认值,这样JSON缺失该字段时会使用默认值:
struct Device: Codable, Identifiable { var id = UUID().uuidString let serialNumber: String = "" let model: String = "" let brand: String = "" }
4. 处理自定义默认字段(如id)
结构体中的id字段有默认值,Codable会自动忽略对该字段的解码,无需手动写CodingKeys。只要字段有明确的默认值(或者是var类型且初始化时赋值),解码过程就不会尝试从JSON中读取该字段。
内容的提问来源于stack exchange,提问作者Lance

