通过Alamofire,想获取数据并将其插入到TableView中,但是在完成插入之前,先加载TableView

时间:2019-01-11 15:51:11

标签: ios swift uitableview alamofire

在标题中,我使用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 :(得分:1)

与其在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()
        }
    }
}

答案 1 :(得分:0)

defer中的代码是在方法“返回”之后或例如在某个循环的当前循环返回之后执行的。

由于viewDidLoad返回Void,因此此方法在调用updateNewsData()之后立即返回,并且它不等待,因此从内部调用的另一个方法返回或在某个闭包内部的代码之后返回已执行(defer在执行某些闭包后不会执行,因为在闭包内部您无法为声明了闭包的方法返回值)。

要修复您的代码,只需在添加文章后重新加载表视图数据

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

答案 2 :(得分:0)

当执行离开当前作用域时,将执行

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()
            }
        }
    }