如何使用Codable协议解析含嵌套JSON字符串的JSON数据
问题分析与解决方案
首先,咱们来拆解下你遇到的解析错误根源:
你的原始JSON里,nativeId字段的值是一个被转义包裹的JSON字符串(比如"{\"app\":\"1234/Car/Native_App\",\"web\":\"/8888/Car/Native_Car_Desktop\"}"),而你当前的代码犯了两个关键错误:
- 设置了
decoder.dataDecodingStrategy = .deferredToData,这个策略会让JSONDecoder尝试把字符串解码成Data类型,但nativeId是普通的JSON字符串,不是Base64编码的二进制数据,直接触发格式错误。 - 即使去掉这个策略,把
nativeId定义为String?只能拿到原始字符串,没法直接使用里面的app和web字段,不符合实际开发需求。
另外你提供的原始JSON里web字段的引号有语法错误,正确的JSON应该是:
{ "yearOfManufacture":"20/9/2018", "carSize":8, "isNew":true, "carAssets":[ { "color":"5761807993001", "nativeId":"{\"app\":\"1234/Car/Native_App\",\"web\":\"/8888/Car/Native_Car_Desktop\"}" } ] }
方案1:仅解析为字符串(快速修复)
如果暂时只需要把nativeId当作字符串存储,不需要解析内部字段,只需要移除错误的解码策略即可:
struct Cars: Codable { var yearOfManufacture: String? var carSize: Int = 0 var isNew: Bool = true var carAssets: [CarAssests]? } struct CarAssests: Codable { var color: String? var nativeId: String? } // 解析代码 let decoder = JSONDecoder() // 移除这行错误的策略:decoder.dataDecodingStrategy = .deferredToData if let jsonData = jsonString.data(using: .utf8) { do { let assets = try decoder.decode(Cars.self, from: jsonData) print(assets) // 如果后续需要解析nativeId内部字段,可以手动二次解码 if let nativeIdStr = assets.carAssets?.first?.nativeId, let nativeData = nativeIdStr.data(using: .utf8) { let nativeDict = try JSONSerialization.jsonObject(with: nativeData) as? [String: String] print("app: \(nativeDict?["app"] ?? "")") print("web: \(nativeDict?["web"] ?? "")") } } catch { print(error) // 打印完整错误,别只看localizedDescription,能拿到更详细的报错信息 } }
方案2:直接解析为结构体(推荐)
如果需要直接使用nativeId里的app和web字段,咱们可以自定义解码逻辑,把嵌套的JSON字符串直接解析成结构体:
步骤1:定义完整的模型结构
struct Cars: Codable { var yearOfManufacture: String? var carSize: Int = 0 var isNew: Bool = true var carAssets: [CarAssests]? } struct CarAssests: Codable { var color: String? var nativeId: NativeId? // 自定义解码逻辑 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) color = try container.decodeIfPresent(String.self, forKey: .color) // 先把nativeId解码成字符串,再转成Data,最后解码成NativeId结构体 if let nativeIdStr = try container.decodeIfPresent(String.self, forKey: .nativeId), let nativeData = nativeIdStr.data(using: .utf8) { nativeId = try JSONDecoder().decode(NativeId.self, from: nativeData) } else { nativeId = nil } } enum CodingKeys: String, CodingKey { case color, nativeId } } // 对应nativeId内部的结构 struct NativeId: Codable { var app: String? var web: String? }
步骤2:正常解析使用
let decoder = JSONDecoder() if let jsonData = jsonString.data(using: .utf8) { do { let assets = try decoder.decode(Cars.self, from: jsonData) print("app字段值:\(assets.carAssets?.first?.nativeId?.app ?? "")") print("web字段值:\(assets.carAssets?.first?.nativeId?.web ?? "")") } catch { print(error) // 打印完整错误信息,方便排查问题 } }
内容的提问来源于stack exchange,提问作者salman siddiqui
相关产品推荐
相关产品推荐

