Swift - 来自URLSession任务的TableView数据源

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift - 来自URLSession任务的TableView数据源相关的知识,希望对你有一定的参考价值。

我必须使用TableView填充一些数据来填充URLSession task。源是一个XML文件,所以我将其解析为任务。解析的结果是一个数组,我传递给另一个填充TableView Delegates使用的另一个数组的函数。

我的问题是在任务结束之前调用TableView Delegates,所以当我启动应用程序时,桌子是空的,除非数据重新加载(所以我知道解析和任务工作正常)。

这是viewDidLoad功能。 listOfApps是我的TableView

    override func viewDidLoad() {

            super.viewDidLoad() 

            fetchData()
            checkInstalledApps(apps: <ARRAY POPULATED>)  

            listOfApps.delegate = self
            listOfApps.dataSource = self

        }
    }

fetchData是我获取XML文件并解析它的函数

    func fetchData() {
        let myUrl = URL(string: "<POST REQUEST>");
        var request = URLRequest(url:myUrl!)
        request.httpMethod = "POST"
        let postString = "firstName=James&lastName=Bond";
        request.httpBody = postString.data(using: String.Encoding.utf8);

        let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in

            self.parser = XMLParser(data: data!)
            self.parser.delegate = self

        }
        task.resume()

    }

checkInstalledApps是我组成TableView Delegates使用的数组的函数。

    func checkInstalledApps(apps: NSMutableArray){
    ....
    installedApps.add(...)
    installedApps.add(...)
    ....
    }

因此,例如,设置行数我计算installedApps元素

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    if (installedApps.count == 0) {
        noApp = true
        return 1
    }
    return installedApps.count
}

这是0.显然,如果我重新加载数据,一切都好。

我的问题是异步调用:首先我使用了可通过GET请求访问的XML,所以我可以使用XMLParser(contentsOf: myUrl),时间不是问题。也许如果XML会成长,也会以这种方式遇到麻烦,但现在我要使用POST请求

我试过用DispatchGroup,用

  • group.enter()之前的super.viewDidLoad
  • group.leave()之后的task.resume()
  • group.wait()之后的checkInstalledApps()

哪个组是let group = DispatchGroup(),但没有。

那么,我怎样才能告诉tableview委托等待任务响应和下一个函数?

提前致谢

答案

我会忘记DispatchGroup,并在这里改变一种思维方式(你不想冻结UI直到响应在这里)。

我相信你可以保留fetchData实现。

XMLParserDelegate.parserDidEndDocument(_:)中,您将收到有关XML已被解析的通知。在该方法中,调用checkInstalledApps来填充模型数据。之后,只需调用listOfApps.reloadData()告诉tableView重新加载新数据。

你想在主线程上调用checkInstalledAppslistOfApps.reloadData()(使用DispatchQueue.main.async {})。

同时保持listOfApps.delegate = selflistOfApps.dataSource = selfviewDidLoad现在。

另一答案

更干净的方法是使用空状态视图/ activityIndi​​cator / loader / progress hud(无论你想要什么),通知用户应用程序正在获取/加载数据,

提取完成后,只需重新加载tableview并删除空状态视图/加载器

另一答案

您的问题是由于您目前无法知道URLSession任务何时结束。 reloadData()调用在提交请求后几乎立即发生,因此您看到空表,并且需要稍后的表重新加载,尽管新的重新加载应该是任务结束的时间。

以下是发生的事情的简化图:enter image description here

完成块提供了易于实施的解决方案。下面你可以找到一个非常简单的(并且可能不完整,因为我没有关于实际xml解析的所有细节)解决方案:

func fetchData(completion: @escaping () -> Void) {
     let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
            self.parser = XMLParser(data: data!)
            self.parser.delegate = self
            completion()
}

override func viewDidLoad() {
    super.viewDidLoad() 
    fetchData() { [weak self] in self?.tableView.reloadData() }
}

基本上,完成块将完成xml数据返回链。

以上是关于Swift - 来自URLSession任务的TableView数据源的主要内容,如果未能解决你的问题,请参考以下文章

如何同步 URLSession 任务的串行队列?

tableview 是空的,但我看到操场上的数据来自 urlsession

Swift URLSession DataTask 在应用程序进入后台时失败

URLSession 实例方法`downloadTask` 错误

swift3.0:NSURLSession的使用

Swift UrlSession 在 UrlSession 中不起作用