Swift 3 - 刷新填充后,异步请求表为空

时间:2017-05-05 22:37:46

标签: swift uitableview asynchronous request alamofire

我是Swift的新手并且正在构建一个应用程序,它在第一页上向我显示带有图像和文本字段的tableview。 我有两个请求,一个用于获取所有图像,另一个用于获取所有名称。 我的问题是,当我同时调用这两个请求时,表格为#34;空白" - 当我下拉并刷新表格时,会显示数据。奇怪的是,当我只做一个请求并且"禁用"另一个。它工作流利。 (针对个别请求进行了测试)。

第一次请求:

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()
            }
        }
    }

的TableView:

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。

1 个答案:

答案 0 :(得分:0)

您的refreshData()函数中存在严重的设计错误

函数getAllToDo()getAllImages()都是异步。换句话说,即使在函数返回后它们仍继续处理。您当前的refreshData错误地认为这样的处理在每个函数返回时结束 - 事实并非如此!因此,您过早离开DispatchGroup。最后,这完美地解释了你的经验观察:

  

似乎在数据完全加载之前,tableView被称为

用于处理异步通信的标准模式是在调用异步函数时将完成处理程序传递给异步函数。例如:

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()
}

您正在推迟您所在的相同队列上的工作 - 不会产生任何性能提升。事实上,相反可能会发生,给定:队列处理开销;锁定成本;上下文切换;等