【问题标题】:Can't get DispatchGroup to work properly in Swift无法让 DispatchGroup 在 Swift 中正常工作
【发布时间】:2018-07-25 07:13:02
【问题描述】:

在更新 UI 之前需要等待一些 api 调用循环完成,但还不知道为什么我的 DispatchGroup.notify() 在 http 调用之前被执行:

override func viewDidAppear(_ animated: Bool) {

    if isFirstLoad {

        ProgressIndicator.shared.showProgressView(self.view)

        let serviceUrl = MobnerServices.service_base+"GetTrainersAround?lat=\(self.currLatitude!)&lon=\(self.currLongitude!)&radius=50"

        Alamofire.request(serviceUrl).responseJSON{ response in
            do{
                guard let responseData = response.data else{
                    print("No data received.")
                    ProgressIndicator.shared.hideProgressView()
                    return
                }

                let dispatchGroup = DispatchGroup()
                let decoder = JSONDecoder()

                let retrievedTrainers = try decoder.decode([STTrainer].self, from: responseData)

                self.trainers = retrievedTrainers
                self.isFirstLoad = false

                for trainer in self.trainers{
                    dispatchGroup.enter()

                    let getUserPictureUrl = MobnerServices.service_base+"GetUserPicture?filename=\(trainer.profilePicturePath)"

                    Alamofire.request(getUserPictureUrl).responseImage { response in
                        guard let image = response.result.value else {
                            print(response.error!.localizedDescription)
                            return
                        }

                        self.trainersPictures.append(STTrainerPicture(userId: trainer.userId, profilePicture: image))
                    }

                    dispatchGroup.leave()
                }

                dispatchGroup.wait()

                ProgressIndicator.shared.hideProgressView()
                self.tableView.reloadData()

            }
            catch{
                print(error.localizedDescription)
            }
        }

    }
}

这里有人给点建议吗? 提前致谢!

【问题讨论】:

  • 你的代码中没有DispatchGroup.notify,那么我们到底在说什么?
  • 我在一些博客中看到我们可以使用 .wait() 而不是 .notify()。
  • 我们当然可以使用wait 而不是notify,但是您的问题不应该问为什么不调用notify。没有notify
  • Guilherme,这些博客具有误导性,因为使用 wait 几乎总是错误的方法。较新的开发人员喜欢wait,因为它简单直观,但会导致糟糕的用户体验并可能带来问题。在此示例中,您将在 wait 处阻塞主线程,因此您将死锁,因为 Alamofire 将无法在该阻塞的主队列上运行其完成处理程序,因此,您将永远无法到达那个leave 电话,它永远不会超过那个@ 987654331@。 notify 模式避免了阻塞主线程,避免了这个问题。
  • @Rob,这是真的。我注意到当使用 .wait() 时,用户界面甚至不会被错误地更新。

标签: ios swift rest alamofire


【解决方案1】:

你的问题是你在错误的地方打电话给dispatchGroup.leave()。它需要在异步调用的完成处理程序中。

let dispatchGroup = DispatchGroup()
let decoder = JSONDecoder()

let retrievedTrainers = try decoder.decode([STTrainer].self, from: responseData)

self.trainers = retrievedTrainers
self.isFirstLoad = false

for trainer in self.trainers{
    dispatchGroup.enter()

    let getUserPictureUrl = MobnerServices.service_base+"GetUserPicture?filename=\(trainer.profilePicturePath)"

    Alamofire.request(getUserPictureUrl).responseImage { response in
        guard let image = response.result.value else {
            print(response.error!.localizedDescription)
            dispatchGroup.leave()
            return
        }

        self.trainersPictures.append(STTrainerPicture(userId: trainer.userId, profilePicture: image))
        dispatchGroup.leave()
    }
}

dispatchGroup.notify(queue: .main) {
    ProgressIndicator.shared.hideProgressView()
    self.tableView.reloadData()
}

您还需要在主队列上执行 UI 更新。

【讨论】:

  • 工作就像一个魅力!关于更新 UI,我将 .wait() 替换为:dispatchGroup.notify(queue: .main){ ProgressIndicator.shared.hideProgressView() self.tableView.reloadData() } 它确实成功了.. 非常感谢
  • 是的,这是处理 UI 更新的好方法。请不要忘记接受可以解决您问题的答案。
  • @Rob 等待在第一个 Alamofire 完成块内,所以它不应该阻止任何东西,这就是我把它留在那里的原因。但我的回答中并不清楚这种情况,所以我会更新它。
  • 是的,wait 在 Alamofire 完成块内,但这些完成块默认在主队列上运行。因此,您将在主线程上等待。你的notify 解决了这个问题!
  • @Rob 我从未使用过 Alamofire,所以我只是假设完成处理程序在后台队列上运行。所以看起来 Alamofire 会自动调用主队列上的完成处理程序。我不喜欢那个设计决定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-05
  • 2017-11-06
相关资源
最近更新 更多