По Alamofire, хотел бы получить данные и вставить их в TableView, но перед завершением вставки, TableView загружается - PullRequest
0 голосов
/ 11 января 2019

Как я пишу в заголовке, я использую Alamofire для получения данных, а затем декодирую их и добавляю в список «articleList», а затем пытаюсь вставить их в TableView, но кажется, что TableView загружается в сначала, а затем данные собираются и вставляются в список. Я хотел бы сделать вставку, а затем загрузить TableView, но я не могу найти решение. Я просто попробовал это, поместив defer в viewDidLoad и сделав tableView.realodData, но он не работает ... Кто-нибудь может дать мне какое-нибудь представление об этой ситуации?

import UIKit
import Alamofire

class NewsViewController: UITableViewController {
    var urlForApi = "https://newsapi.org/v2/top-headlines?country=jp&category=technology&apiKey=..."

    var articleList = [Article]()

    override func viewDidLoad() {
        super.viewDidLoad()
        updateNewsData()
        defer {
            tableView.reloadData()
        }
    }

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

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

        cell.textLabel?.text = articleList[indexPath.row].title

        return cell
    }

    //    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    //
    //    }

    func updateNewsData() {
        getNewsData() { (articles) in
            guard let articleArray = articles?.articles else
            {fatalError("cannot get articles.")}

            for article in articleArray {
                self.articleList.append(article)
            }

            print("insert is done")
        }
    }

    func getNewsData(completion: @escaping (ArticlesListResult?) -> Void) {
        Alamofire.request(urlForApi, method: .get)
            .responseJSON { response in
                if response.result.isSuccess {
                    if let data = response.data {
                        let articles = try? JSONDecoder().decode(ArticlesListResult.self, from: data)
                        completion(articles)
                    }
                } else {
                    print("Error: \(String(describing: response.result.error))")
                }
        }
    }
}

Ответы [ 3 ]

0 голосов
/ 11 января 2019

Defer блок будет выполнен, когда выполнение выйдет из текущей области, с другой стороны, ваш запрос является асинхронным блоком, что означает, что при вызове tableView.reloadData () запрос, возможно, все еще находится в процессе.

Вам нужно вызвать reloadData после завершения запроса:

override func viewDidLoad() {
    super.viewDidLoad()
    updateNewsData()
}

...

func updateNewsData() {
        getNewsData() { (articles) in
            guard let articleArray = articles?.articles else
            {fatalError("cannot get articles.")}

            for article in articleArray {
                self.articleList.append(article)
            }

            print("insert is done")

            DispatchQueue.main.async {
                tableView.reloadData()
            }
        }
    }
0 голосов
/ 11 января 2019

Вместо записи tableView.reloadData() в методе viewDidLoad, вы должны написать его после завершения добавления всех articles в массиве articleList.

Пример кода:

viewDidLoad() должно быть как:

override func viewDidLoad() {
    super.viewDidLoad()
    updateNewsData()
}

updateNewsData() должно быть как:

func updateNewsData() {
    getNewsData() { (articles) in
        guard let articleArray = articles?.articles else
        {fatalError("cannot get articles.")}

        articleList.append(contentsOf: articleArray)
        DispatchQueue.main.async {
            tableView.reloadData()
        }
    }
}
0 голосов
/ 11 января 2019

Код внутри defer выполняется после «возврата» метода или, например, после возврата текущего цикла некоторого цикла

Так как viewDidLoad возвращает Void, этот метод возвращается сразу после вызова updateNewsData(), и он не ждет, тогда другой метод, который был вызван изнутри, возвращает или после выполнения кода внутри некоторого замыкания (defer isn не выполняется после выполнения некоторого замыкания, поскольку внутри замыкания нельзя вернуть значение для метода, в котором было объявлено закрытие).

Чтобы исправить ваш код, просто перезагрузите данные табличного представления после добавления статей

for article in articleArray {
    self.articleList.append(article)
}
tableView.reloadData()
...