【问题标题】:Swift 3 - Async Request table empty, after refresh filledSwift 3 - 异步请求表为空,刷新后填充
【发布时间】:2017-10-04 12:16:03
【问题描述】:

我是 Swift 新手,目前正在构建一个应用程序,它在第一页向我展示了一个带有图像和文本字段的表格视图。 我有两个请求,一个获取所有图像,一个获取所有名称。 我的问题是,当我调用这两个请求时,表是“空的”——当我下拉并刷新表时,数据就会出现。奇怪的是,当我只做一个请求并“禁用”另一个请求时。它运行流畅。 (针对两个单独的请求对此进行了测试)。

第一个请求:

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

表格视图:

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。

【问题讨论】:

    标签: swift uitableview asynchronous request alamofire


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      • 2012-07-25
      • 2011-12-11
      • 1970-01-01
      • 2017-03-22
      • 2021-04-22
      • 1970-01-01
      相关资源
      最近更新 更多