我是 Swift 的新手,目前正在构建一个应用程序,它在第一页上向我显示一个带有图像和文本字段的表格 View 。 我有两个请求,一个是获取所有图像,一个是获取所有名称。 我的问题是,当我同时调用这两个请求时,表格是“空的”——当我下拉并刷新表格时,数据就会出现。奇怪的是,当我只执行一个请求并“禁用”另一个请求时。它运行流畅。 (针对两个单独的请求对此进行了测试)。
第一个请求:
func getAllToDo(){
let url:String = "XXXXXXXXXXX"
let getAllToDosRequest = Alamofire.request(url)
getAllToDosRequest.responseJSON{ response in
switch response.result{
case .success(let JSON):
let response = JSON as! NSArray
self.listOfTodos.removeAll()
for item in response {
let obj = item as! NSDictionary
let toDo = ToDo(id: obj["id_ToDo"] as! Int, name: obj["name"] as! String, todo_description: obj["description"] as! String)
self.listOfTodos.append(toDo)
}
case .failure(let error):
print("Request failed with error: \(error)")
}
}
}
第二个请求:
func getAllImages(){
let url:String = "XXXXXXXXXXXXXXX"
let getAllImagesRequest = Alamofire.request(url)
getAllImagesRequest.responseJSON{ response in
switch response.result{
case .success(let JSON):
let response = JSON as! NSArray
self.listOfImages.removeAll()
for item in response {
let obj = item as! NSDictionary
let image = Image(id: obj["id"] as! Int, binary: obj["binary"] as! String, name: obj["name"] as! String)
self.listOfImages.append(image)
}
case .failure(let error):
print("Request failed with error: \(error)")
}
}
}
线程处理:
func refreshData(){
let myGroup = DispatchGroup()
for i in 0 ..< 2 {
myGroup.enter()
if(i == 0){
getAllImages()
print("Finished request \(i)")
myGroup.leave()
}
if(i == 1){
getAllToDo()
print("Finished request \(i)")
myGroup.leave()
}
}
myGroup.notify(queue: .main){
print("All finished")
DispatchQueue.main.async {
self.tableView.reloadData()
self.refreshControl.endRefreshing()
}
}
}
表格 View :
override func viewDidLoad() {
super.viewDidLoad()
refreshData()
if #available(iOS 10.0, *){
tableView.refreshControl = refreshControl
} else{
tableView.addSubview(refreshControl)
}
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return listOfTodos.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let todo = listOfTodos[indexPath.row]
let image = listOfImages[indexPath.row]
cell.myLabel.text = todo.name
cell.myImage.image = convert64BaseToImage(binary: image.binary)
return(cell)
}
如果我按照代码所示进行操作,tableView 在启动后是空的,但是当我下拉时它有数据。我究竟做错了什么?如果我只执行一个单独的请求,tableView 会被填满...似乎在数据完全加载之前调用了 tableView。
最佳答案
您的 refreshData()
函数中存在严重的设计错误。
函数 getAllToDo()
和 getAllImages()
都是异步。换句话说,即使在函数返回后,它们也会继续处理。您当前的 refreshData
错误地假设此类处理在每个函数返回时结束 - 事实并非如此!因此,您离开 DispatchGroup
的时间过早。最后,这完美地解释了您的经验观察:
It seems like that the tableView is called before the data is completely loaded.
处理异步通信的标准模式是在调用异步函数时将完成处理程序传递给异步函数。例如:
func getAllToDo(completion: () -> Void) {
...
getAllToDosRequest.responseJSON { response in
switch response.result {
...
}
completion() // Processing is done!
}
}
然后,在您的 refreshData()
函数中,定义一个适当的完成处理程序:
getAllToDo {
print("Finished request \(i)")
myGroup.leave()
}
当然,您也必须对 getAllImages()
函数进行相同的重构。
顺便说一下,你可以简化这个:
myGroup.notify(queue: .main){
print("All finished")
DispatchQueue.main.async {
self.tableView.reloadData()
self.refreshControl.endRefreshing()
}
}
作为:
myGroup.notify(queue: .main){
print("All finished")
self.tableView.reloadData()
self.refreshControl.endRefreshing()
}
您正在推迟您所在的相同队列的工作——这不会带来任何性能提升。事实上,相反可能会发生,因为:队列处理开销;锁定成本;上下文切换;等
关于Swift 3 - 异步请求表为空,刷新后填充,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43814697/