我必须使用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委托等待任务响应和下一个函数?
提前致谢
答案 0 :(得分:1)
我会忘记DispatchGroup
,并在这里改变一种思维方式(你不想冻结用户界面,直到响应在这里)。
我相信您可以保留fetchData
实施原样。
在XMLParserDelegate.parserDidEndDocument(_:)
中,您将收到有关XML已被解析的通知。在该方法中,调用checkInstalledApps
来填充模型数据。之后,只需调用listOfApps.reloadData()
告诉tableView重新加载新数据。
您想在主线程上调用checkInstalledApps
和listOfApps.reloadData()
(使用DispatchQueue.main.async {}
)。
同时将listOfApps.delegate = self
和listOfApps.dataSource = self
保留在viewDidLoad
中,就像现在一样。
答案 1 :(得分:0)
更简洁的方法是使用空状态视图/ activityIndicator / loader / progress hud(无论你想要什么),通知用户应用程序正在获取/加载数据,
完成提取后,只需重新加载tableview并删除空状态视图/加载程序
答案 2 :(得分:0)
您的问题是由于您目前无法知道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数据返回链。