调用PokeApi获取宝可梦名称遇CodingKeys错误,结构体存疑求解决
解决PokeApi数据解析错误:No value associated with key CodingKeys(stringValue: "index"...)
错误信息
"No value associated with key CodingKeys(stringValue: "index", intValue: nil) ("index").", underlyingError: nil
问题代码
import UIKit class ListViewController: UIViewController { @IBOutlet weak var pokemon1: UILabel! @IBOutlet weak var pokemon2: UILabel! @IBOutlet weak var pokemon3: UILabel! @IBOutlet weak var pokemon4: UILabel! @IBOutlet weak var pokemon5: UILabel! let url = "https://pokeapi.co/api/v2/pokemon" override func viewDidLoad() { super.viewDidLoad() fetchData(from: url) } func fetchData(from url: String) { let url = URL(string: url) let defaultSession = URLSession(configuration: .default) let dataTask = defaultSession.dataTask(with: url!) { (data: Data?, response: URLResponse?, error: Error?) in if(error != nil) { print(String(describing: error)) return } var json: Pokemon do { json = try JSONDecoder().decode(Pokemon.self, from: data!) Swift.print(json) // DispatchQueue.main.async { // self.pokemon1.text = json.name // self.pokemon3.text = json[2].name // self.pokemon4.text = json[3].name // self.pokemon5.text = json[4].name // //callback: fonction que j'appelle à la suite d'un évènement // } } catch { print(error) return } } dataTask.resume() // Commence la dataTask si elle n'est pas en marche actuellement } struct Pokemon: Codable { let results: Results } struct Results: Codable { let name: String let index: String } }
API返回数据
{ "count": 1154, "next": "https://pokeapi.co/api/v2/pokemon?offset=20&limit=20", "previous": null, "results": [ { "name": "bulbasaur", "url": "https://pokeapi.co/api/v2/pokemon/1/" }, { "name": "ivysaur", "url": "https://pokeapi.co/api/v2/pokemon/2/" }, { "name": "venusaur", "url": "https://pokeapi.co/api/v2/pokemon/3/" }, { "name": "charmander", "url": "https://pokeapi.co/api/v2/pokemon/4/" }, { "name": "charmeleon", "url": "https://pokeapi.co/api/v2/pokemon/5/" }, { "name": "charizard", "url": "https://pokeapi.co/api/v2/pokemon/6/" }, { "name": "squirtle", "url": "https://pokeapi.co/api/v2/pokemon/7/" }, { "name": "wartortle", "url": "https://pokeapi.co/api/v2/pokemon/8/" }, { "name": "blastoise", "url": "https://pokeapi.co/api/v2/pokemon/9/" }, { "name": "caterpie", "url": "https://pokeapi.co/api/v2/pokemon/10/" }, { "name": "metapod", "url": "https://pokeapi.co/api/v2/pokemon/11/" }, { "name": "butterfree", "url": "https://pokeapi.co/api/v2/pokemon/12/" }, { "name": "weedle", "url": "https://pokeapi.co/api/v2/pokemon/13/" }, { "name": "kakuna", "url": "https://pokeapi.co/api/v2/pokemon/14/" }, { "name": "beedrill", "url": "https://pokeapi.co/api/v2/pokemon/15/" }, { "name": "pidgey", "url": "https://pokeapi.co/api/v2/pokemon/16/" }, { "name": "pidgeotto", "url": "https://pokeapi.co/api/v2/pokemon/17/" }, { "name": "pidgeot", "url": "https://pokeapi.co/api/v2/pokemon/18/" }, { "name": "rattata", "url": "https://pokeapi.co/api/v2/pokemon/19/" }, { "name": "raticate", "url": "https://pokeapi.co/api/v2/pokemon/20/" } ] }
问题分析与修正方案
错误根源在于Codable结构体定义和API返回数据不匹配:
- 错误1:API中
results是数组([]包裹),但代码里定义为单个Results对象,类型不匹配 - 错误2:API返回的结果里没有
index字段,只有name和url,错误定义的index导致解析失败
修正后的代码
import UIKit class ListViewController: UIViewController { @IBOutlet weak var pokemon1: UILabel! @IBOutlet weak var pokemon2: UILabel! @IBOutlet weak var pokemon3: UILabel! @IBOutlet weak var pokemon4: UILabel! @IBOutlet weak var pokemon5: UILabel! let url = "https://pokeapi.co/api/v2/pokemon" override func viewDidLoad() { super.viewDidLoad() fetchData(from: url) } func fetchData(from url: String) { guard let url = URL(string: url) else { print("无效的URL") return } let defaultSession = URLSession(configuration: .default) let dataTask = defaultSession.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } if let error = error { print("请求错误:\(error)") return } guard let data = data else { print("未获取到数据") return } do { let pokemonResponse = try JSONDecoder().decode(PokemonResponse.self, from: data) print(pokemonResponse) DispatchQueue.main.async { // 避免数组越界 if pokemonResponse.results.count >= 1 { self.pokemon1.text = pokemonResponse.results[0].name } if pokemonResponse.results.count >= 2 { self.pokemon2.text = pokemonResponse.results[1].name } if pokemonResponse.results.count >= 3 { self.pokemon3.text = pokemonResponse.results[2].name } if pokemonResponse.results.count >= 4 { self.pokemon4.text = pokemonResponse.results[3].name } if pokemonResponse.results.count >= 5 { self.pokemon5.text = pokemonResponse.results[4].name } } } catch { print("解析错误:\(error)") return } } dataTask.resume() } struct PokemonResponse: Codable { let count: Int let next: String? let previous: String? let results: [PokemonResult] } struct PokemonResult: Codable { let name: String let url: String } }
关键修改点
- 重命名结构体为
PokemonResponse,明确对应API的完整响应,添加API返回的count、next、previous字段(可按需删除) - 将
results字段类型改为[PokemonResult],匹配API的数组结构 - 将
Results重命名为PokemonResult,并把index替换为API存在的url字段 - 增加空值判断和数组越界防护,避免崩溃
- 使用
[weak self]防止循环引用
内容的提问来源于stack exchange,提问作者Amaury Gimonnet
相关产品推荐
相关产品推荐

