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

Swift如何对顶层键为未知值的JSON进行Decodable解码

错误根因

你收到的报错已经明确指出问题:JSON顶层结构是字典,但你调用decode方法时传入的参数是[Pokemon].self(数组类型),类型不匹配导致解码失败。

解决方案

方案1:最简实现(推荐)

不需要修改原有PokemonInfo模型,直接将顶层结构解码为[String: PokemonInfo]类型(键为动态的宝可梦英文名,值为宝可梦信息结构体):

// 原有模型无需调整
struct PokemonInfo: Decodable {
    var name: String
    var number: Int
}

// 解码代码直接写为
let decodedDict = try JSONDecoder().decode([String: PokemonInfo].self, from: data)

如果需要得到你定义的Pokemon结构体数组,补全Pokemon定义后遍历字典转换即可:

struct Pokemon: Decodable {
    var key: String // 对应顶层动态键,比如"pikachu"
    var pokemonInfo: PokemonInfo
}

// 字典转数组
let pokemonList = decodedDict.map { Pokemon(key: $0.key, pokemonInfo: $0.value) }

方案2:一步解码为数组

如果不想手动做字典转数组的步骤,可以自定义解码逻辑,直接把顶层动态键字典解析为Pokemon数组:

// 定义动态CodingKey用于匹配不确定的顶层键
private struct DynamicCodingKey: CodingKey {
    var stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
        intValue = nil
    }
    var intValue: Int?
    init?(intValue: Int) { return nil }
}

// 定义数组包装结构体,自定义解码逻辑
struct PokemonList: Decodable {
    let items: [Pokemon]
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DynamicCodingKey.self)
        var tempItems = [Pokemon]()
        for key in container.allKeys {
            let info = try container.decode(PokemonInfo.self, forKey: key)
            tempItems.append(Pokemon(key: key.stringValue, pokemonInfo: info))
        }
        items = tempItems
    }
}

// 解码时直接传入PokemonList.self即可
let result = try JSONDecoder().decode(PokemonList.self, from: data)
let pokemonList = result.items

内容的提问来源于stack exchange,提问作者Dannis Case

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 10:57:03