Swift中嵌套JSON转Model遇keyNotFound错误,寻求解决方案
Swift嵌套JSON解析错误解决方法
问题场景
API返回的嵌套JSON
{ "data": [ { "_id": "63d9d2d57c0cfe791b2b19f6", "step": { "_id": "step1", "status": "STARTED", "children": [ { "_id": "step2", "status": "NOT_STARTED", "children": [ { "_id": "step3", "status": "NOT_STARTED", "children": [ { "_id": "step3", "status": "NOT_STARTED" } ] } ] } ] }, "status": "IN_PROGRESS", "createdBy": "2700930039" } ] }
自定义的Decodable结构体
struct NestedJsonModel:Decodable { var data:[LotData]} struct LotData:Decodable { var _id: String var step: StepDetails var status: String var createdBy: String} struct StepDetails:Decodable { var _id: String var status: String var children: [ChildSteps]} struct ChildSteps:Decodable { var _id: String var status: String var children: [StepDetails] //because children contains the same model as Step Details}
解码代码
let jsonData = data.data(using: .utf8)! do { let decoder = JSONDecoder() let tableData = try decoder.decode(NestedJsonModel.self, from: jsonData) result = tableData.data print("****************") print(result!) print("****************") }catch { print (error) }
触发的错误信息
keyNotFound(CodingKeys(stringValue: "children", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "step", intValue: nil), CodingKeys(stringValue: "children", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "children", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"children\", intValue: nil) (\"children\").", underlyingError: nil))
错误原因
- 字段非必填但模型设为必填:JSON最内层的
step3节点没有children字段,但StepDetails和ChildSteps中children被定义为非可选数组,解码时找不到对应key直接报错。 - 冗余结构体定义:
StepDetails和ChildSteps字段完全一致,分开定义不仅冗余,还会导致嵌套层级匹配混乱。
解决方案
修正后的Decodable模型
方案1:将children设为可选数组
struct NestedJsonModel: Decodable { var data: [LotData] } struct LotData: Decodable { var _id: String var step: Step var status: String var createdBy: String } // 合并为单个递归结构体,适配嵌套层级 struct Step: Decodable { var _id: String var status: String var children: [Step]? // 设为可选,适配无children的节点 }
方案2:给children设置默认空数组(避免nil)
如果希望children始终为数组而非nil,可自定义解码逻辑:
struct NestedJsonModel: Decodable { var data: [LotData] } struct LotData: Decodable { var _id: String var step: Step var status: String var createdBy: String } struct Step: Decodable { var _id: String var status: String var children: [Step] = [] // 默认空数组 enum CodingKeys: String, CodingKey { case _id, status, children } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) _id = try container.decode(String.self, forKey: ._id) status = try container.decode(String.self, forKey: .status) // 无children字段时使用默认空数组 children = try container.decodeIfPresent([Step].self, forKey: .children) ?? [] } }
说明
- 合并
StepDetails和ChildSteps为Step结构体,通过递归引用自己完美匹配JSON的嵌套层级。 - 将
children设为可选或默认空数组,彻底解决无该字段时的解码报错问题。
内容的提问来源于stack exchange,提问作者Sam4u
相关产品推荐
相关产品推荐

