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
相关产品推荐
相关产品推荐

