首页 > 解决方案 > 成功解析 JSON 后,应该存储 JSON 的数组为空

问题描述

 var pokemons = [Pokemon]()

    func loadJSON() {
        let url = "https://pokeapi.co/api/v2/pokemon/"
        guard let urlObj = URL(string: url) else { return }

        URLSession.shared.dataTask(with: urlObj) {(data, response, error) in
            guard let data = data else { return }

            do {
                let pokedex = try JSONDecoder().decode(Pokedex.self, from: data)

                for pokemon in pokedex.results {
                    guard let jsonURL = pokemon.url else { return }
                    guard let newURL = URL(string: jsonURL) else { return }

                    URLSession.shared.dataTask(with: newURL) {(data, response, error) in
                        guard let data = data else { return }

                        do {
                            let load = try JSONDecoder().decode(Pokemon.self, from: data)
                            self.pokemons.append(load)

                        } catch let jsonErr {
                            print("Error serializing inner JSON:", jsonErr)
                        }
                    }.resume()
                }
            } catch let jsonErr{
                print("Error serializing JSON: ", jsonErr)
            }
        }.resume()
    }

这段代码编译并运行良好,但是当我之后检查它的大小时,数组 pokemons 返回的计数为 0。这很奇怪,因为如果我在 pokemons.append(load) 之后循环遍历数组,它会吐出一堆数据。就好像数据一旦超出 JSON 的范围就会丢失。我的数组是否需要通过引用或其他方式传递?我正在寻找数据并将其放入 UITableView,但到目前为止没有显示任何内容。

override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.title = "Pokemon"
        navigationController?.navigationBar.prefersLargeTitles = true
        loadJSON()
        print(pokemons.count) //Prints 0
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId)
    }

    override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let label = UILabel()
        label.text = "By Id"
        label.backgroundColor = UIColor.lightGray
        return label
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return pokemons.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)

        let name = pokemons[indexPath.row].name

        cell.textLabel?.text = "\(name) Section:\(indexPath.section) Row:\(indexPath.row)"
        return cell
    }

标签: iosiphoneswift

解决方案


你要么需要

self.pokemons.append(load)
DispatchQueue.main.async {
  self.tableView.reloadData()
}

或写一个完成


异步调用是不与函数编写代码串联的东西,而是异步运行直到它完成然后它通知它的回调,并且在你的代码中,异步方法是URLSession.shared.dataTask在后台线程中运行的(这就是为什么你必须在DispatchQueue.main.async里面插入它刷新 UI ) 并将串行执行留在主线程,以确保您可以阻塞主线程,直到使用类似Data(contentsOf:url)而不是的方法返回响应,URLSession.shared.dataTask但这不是一个好主意


推荐阅读