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

时间:2018-03-01 15:23:35

标签: ios swift uitableview asynchronous

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

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

这是viewDidLoad功能。 listOfAppsTableView

    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.viewDidLoadgroup.leave()
  • 之后
  • task.resume()group.wait()
  • 之后
  • checkInstalledApps()

其中,群组为let group = DispatchGroup(),但没有。

那么,我如何告诉tableview委托等待任务响应和下一个函数?

提前致谢

3 个答案:

答案 0 :(得分:1)

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

我相信您可以保留fetchData实施原样。

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

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

同时将listOfApps.delegate = selflistOfApps.dataSource = self保留在viewDidLoad中,就像现在一样。

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

您的问题是由于您目前无法知道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数据返回链。