我必须使用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重新加载新数据。
你想在主线程上调用checkInstalledApps
和listOfApps.reloadData()
(使用DispatchQueue.main.async {}
)。
同时保持listOfApps.delegate = self
和listOfApps.dataSource = self
在viewDidLoad
现在。
更干净的方法是使用空状态视图/ activityIndicator / loader / progress hud(无论你想要什么),通知用户应用程序正在获取/加载数据,
提取完成后,只需重新加载tableview并删除空状态视图/加载器
您的问题是由于您目前无法知道URLSession
任务何时结束。 reloadData()
调用在提交请求后几乎立即发生,因此您看到空表,并且需要稍后的表重新加载,尽管新的重新加载应该是任务结束的时间。
完成块提供了易于实施的解决方案。下面你可以找到一个非常简单的(并且可能不完整,因为我没有关于实际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数据返回链。