Swift中Codable解析JSON出现keyNotFound(HasError)错误求助
排查JSONDecoder解码失败的问题
咱们来一步步拆解你遇到的keyNotFound错误,其实背后藏着几个Codable模型和JSON结构不匹配的问题:
错误原因分析
- HasError类型不匹配:原始JSON里
HasError是字符串值"FALSE",但你在WebResponse里把它定义成了Bool类型——JSONDecoder没法自动把字符串"FALSE"转成Bool,这会直接导致解码失败。 - ResultData的CodingKeys完全错误:你的
ResultData结构体里,CodingKeys把resultData映射到"ResultData",但原始JSON里ResultData下面直接是"C"字段,这个映射逻辑完全不对,解码器找不到对应的键。 - CData里的字段名不匹配:
CData里的types字段映射的是"Types",但原始JSON里对应的是"Type",少了个后缀"s",导致解码器找不到该字段。 - 遗漏了C下的U字段:原始JSON里
C对象还有一个"U"子对象,你的CData里没定义这个字段,默认情况下JSONDecoder遇到未知键会报错(虽然当前报错是HasError,但这个问题也得一起解决才能正常解码)。
解决方案
咱们逐个修正这些问题:
1. 修正HasError的类型处理
把WebResponse里的HasError改成String类型,再通过计算属性转成Bool值,这样既兼容JSON的字符串格式,又能在代码里方便使用Bool逻辑:
struct WebResponse: Codable { var hasError: String var responseMessage: String var result: String var resultData: ResultData // 计算属性,把字符串转成Bool var isError: Bool { return hasError.uppercased() == "TRUE" } enum CodingKeys: String, CodingKey { case hasError = "HasError" case responseMessage = "ResponseMessage" case result = "Result" case resultData = "ResultData" } }
2. 修正ResultData的结构
ResultData应该直接包含C对象,而不是错误地映射到ResultData本身:
struct ResultData: Codable { var c: CData enum CodingKeys: String, CodingKey { case c = "C" } }
3. 修正CData的字段名并补充U字段
把types改成type(对应JSON里的"Type"),同时补充U的子结构体和字段:
// 新增U字段对应的结构体 struct UData: Codable { var emailVerified: String enum CodingKeys: String, CodingKey { case emailVerified = "EmailVerified" } } struct CData: Codable { var corporateId: String var customerId: String var customerName: String var gcmid: String var loyaltyPoint: String var oldGCMID: String var type: String var userName: String var u: UData? // 用可选类型,防止万一接口返回时没有这个字段 enum CodingKeys: String, CodingKey { case corporateId = "CorporateId" case customerId = "CustomerId" case customerName = "CustomerName" case gcmid = "GCMID" case loyaltyPoint = "LoyaltyPoint" case oldGCMID = "OldGCMID" case type = "Type" case userName = "UserName" case u = "U" } }
4. 解码时允许忽略未知键(可选)
如果接口可能返回未定义的字段,可以给JSONDecoder设置忽略未知键,避免不必要的报错:
let decoder = JSONDecoder() decoder.unknownKeysPolicy = .ignore // 忽略未知键 let jsonRes = try decoder.decode(WebResponse.self, from: dataFromString) print(jsonRes)
修正后的完整测试代码
import Foundation struct UData: Codable { var emailVerified: String enum CodingKeys: String, CodingKey { case emailVerified = "EmailVerified" } } struct CData: Codable { var corporateId: String var customerId: String var customerName: String var gcmid: String var loyaltyPoint: String var oldGCMID: String var type: String var userName: String var u: UData? enum CodingKeys: String, CodingKey { case corporateId = "CorporateId" case customerId = "CustomerId" case customerName = "CustomerName" case gcmid = "GCMID" case loyaltyPoint = "LoyaltyPoint" case oldGCMID = "OldGCMID" case type = "Type" case userName = "UserName" case u = "U" } } struct ResultData: Codable { var c: CData enum CodingKeys: String, CodingKey { case c = "C" } } struct WebResponse: Codable { var hasError: String var responseMessage: String var result: String var resultData: ResultData var isError: Bool { hasError.uppercased() == "TRUE" } enum CodingKeys: String, CodingKey { case hasError = "HasError" case responseMessage = "ResponseMessage" case result = "Result" case resultData = "ResultData" } } // 测试解码逻辑 let jsonString = """ { "WebResponse": { "HasError": "FALSE", "ResponseMessage": "Signed in Successfully.", "Result": "SUCCESS", "ResultData": { "C": { "CustomerId": "656", "CustomerName": "swift son", "UserName": "swift@infinx.com", "Type": "FORM", "OldGCMID": "eA5RV0TSCoY:APA91bFea67cIlKlVes6Scdgth4CiHSzpk78hE89953-l6gK4O9xflYAs0p24jzccBtqQgAMoRaEM4SOdJ1546QDtYk2nm64cZurwz58c9Pmww4JLRDA7wtWSktpdFdVkX94VoiSCPdm", "GCMID": "", "LoyaltyPoint": "0", "CorporateId": "19", "U": { "EmailVerified": "1" } } } } } """ if let data = jsonString.data(using: .utf8) { do { let decoder = JSONDecoder() decoder.unknownKeysPolicy = .ignore let response = try decoder.decode(WebResponse.self, from: data) print("解码成功:\(response)") print("是否有错误:\(response.isError)") } catch { print("解码失败:\(error)") } }
这样修改后,就能成功解码你的JSON数据了。
内容的提问来源于stack exchange,提问作者Swift Lover




