Swift解码含重复同名键的JSON失败原因及解决方法
Swift 解码含同名键的JSON问题解决
1. 解码失败的原因
你的JSON是一个包含3个元素的数组:
- 第1、3个元素仅包含
errors字段,无data字段 - 第2个元素仅包含
data字段,无errors字段
你定义的CsrfData结构体中,data是必填的非可选属性,而Swift的JSONDecoder默认要求结构体的所有非可选属性必须在JSON中存在。当解码数组的第1个元素时,解码器找不到data键,直接抛出keyNotFound错误——这和你是否注释掉errors字段无关。
2. Swift中解码含同名键的JSON的解决方案
要处理这种数组元素结构不一致(部分带errors、部分带data)的情况,核心是让结构体同时兼容两种字段,并将它们设为可选类型:
修改后的结构体定义
struct CsrfExtensions: Decodable { let code: String let reason: String } struct CsrfErrorsArray: Decodable { let extensions: CsrfExtensions let message: String // 按需取消注释使用 } struct CsrfToken: Decodable { let __typename: String let csrfToken: String let appSessionToken: String } struct CreateCsrfToken: Decodable { let createCsrfToken: CsrfToken } struct CsrfData: Decodable { let errors: [CsrfErrorsArray]? // 设为可选字段 let data: CreateCsrfToken? // 设为可选字段 }
解码后逻辑处理
解码完成后,你可以过滤出包含有效data的元素,同时也能处理错误信息:
do { let csrfDataArray: [CsrfData] = try JSONDecoder().decode([CsrfData].self, from: uData) // 提取有效data数据 if let validEntry = csrfDataArray.first(where: { $0.data != nil }) { let tokenInfo = validEntry.data?.createCsrfToken let csrfToken = tokenInfo?.csrfToken let appSessionToken = tokenInfo?.appSessionToken // 后续业务逻辑处理 } // 遍历处理错误信息 csrfDataArray.forEach { entry in if let errors = entry.errors { errors.forEach { error in print("错误码:\(error.extensions.code),原因:\(error.extensions.reason)") } } } } catch { print("解码失败:\(error.localizedDescription)") }
进阶:自定义解码逻辑(可选)
如果需要更精细的解码控制,可以手动实现init(from decoder:)方法:
struct CsrfData: Decodable { let errors: [CsrfErrorsArray]? let data: CreateCsrfToken? init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 尝试解码errors,不存在则返回nil errors = try container.decodeIfPresent([CsrfErrorsArray].self, forKey: .errors) // 尝试解码data,不存在则返回nil data = try container.decodeIfPresent(CreateCsrfToken.self, forKey: .data) } enum CodingKeys: String, CodingKey { case errors, data } }
这种方式可以完全掌控解码流程,避免自动解码的潜在问题。
内容的提问来源于stack exchange,提问作者tommy
相关产品推荐
相关产品推荐

