Массив, который должен хранить JSON, после успешного анализа JSON пуст - PullRequest
0 голосов
/ 25 ноября 2018
 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
    }

1 Ответ

0 голосов
/ 25 ноября 2018

Вам нужно либо

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

, либо написать завершение


. Асинхронный вызов - это то, что не идет последовательно с кодом, написанным функцией, но выполняется асинхронно до тех пор, показавершается, затем уведомляет об обратном вызове, и в вашем коде асинхронный метод - URLSession.shared.dataTask, который выполняется в фоновом потоке (вот почему вы должны вставить DispatchQueue.main.async в него, чтобы обновить пользовательский интерфейс) и наверняка оставить последовательное выполнение в основном потоке.Вы можете заблокировать основной поток до тех пор, пока ответ не вернется, используя метод, подобный Data(contentsOf:url) вместо URLSession.shared.dataTask, но это не очень хорошая идея

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...