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

iOS Swift使用Decodable解析LOL英雄详情JSON动态Key适配问题

动态Key类JSON的Decodable解析方案

你遇到的是JSON顶层存在动态未知Key的典型场景,Swift Decodable原生支持该场景的解析,无需手动枚举所有英雄ID作为CodingKeys,有两种常用解决方案:


方案1:直接用字典类型接收动态Key层(最推荐,改造成本最低)

拳头的单英雄详情接口返回数据本质是[英雄ID: 英雄详情]的字典结构,你无需额外定义外层DataClass结构体,直接将响应数据解码为[String: HeroDetail]类型即可,其中HeroDetail是你已经写好的单个英雄详情解析结构体,无需修改。
示例代码:

// 你原有已实现的单英雄详情结构体,不需要做任何调整
struct HeroDetail: Decodable {
    let id: String
    let name: String
    let title: String
    let stats: [String: Double]
    // 其他你需要的字段按需补充
}

// 解析逻辑
do {
    // 直接解码为[String: HeroDetail]字典
    let heroMap = try JSONDecoder().decode([String: HeroDetail].self, from: apiResponseData)
    // 当前请求的英雄ID你可以从拼接请求URL的参数里拿到,直接取对应值即可
    let targetHeroId = "当前请求的英雄ID,例如ahri"
    guard let heroDetail = heroMap[targetHeroId] else {
        throw NSError(domain: "ParseError", code: -1, userInfo: [NSLocalizedDescriptionKey: "未找到对应英雄数据"])
    }
    // 拿到英雄详情后做后续业务处理
} catch {
    print("解析失败:\(error.localizedDescription)")
}

方案2:自定义解码初始化器适配动态Key(适合需要封装外层结构体的场景)

如果你需要统一封装响应结构,可以自定义动态CodingKey和解码初始化器实现解析,无需枚举所有英雄ID:
示例代码:

// 自定义外层响应结构体
struct SingleHeroResponse: Decodable {
    // 动态获取的英雄ID
    let heroId: String
    // 英雄详情
    let detail: HeroDetail
    
    // 自定义动态CodingKey,支持任意字符串类型的Key
    private struct DynamicCodingKey: CodingKey {
        var stringValue: String
        var intValue: Int?
        init?(stringValue: String) {
            self.stringValue = stringValue
            self.intValue = nil
        }
        init?(intValue: Int) {
            self.stringValue = "\(intValue)"
            self.intValue = intValue
        }
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DynamicCodingKey.self)
        // 单英雄接口仅返回1个键值对,直接取第一个Key即可
        guard let firstKey = container.allKeys.first else {
            throw DecodingError.dataCorrupted(.init(codingPath: [], debugDescription: "响应数据无英雄信息"))
        }
        self.heroId = firstKey.stringValue
        self.detail = try container.decode(HeroDetail.self, forKey: firstKey)
    }
}

// 解析逻辑
do {
    let response = try JSONDecoder().decode(SingleHeroResponse.self, from: apiResponseData)
    print("英雄ID:\(response.heroId),英雄名称:\(response.detail.name)")
} catch {
    print("解析失败:\(error.localizedDescription)")
}

补充说明

  • 两种方案都不需要调整你已写好的单英雄详情解析逻辑,仅需要修改外层的解析方式即可
  • 如果你后续需要批量拉取全量英雄详情,方案1可以直接合并所有响应字典得到全量英雄ID到详情的映射表,使用效率更高

内容的提问来源于stack exchange,提问作者이진성

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 04:57:03