You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:10:30