我连续进行多个api调用,当我最终推送到下一个视图控制器时,我的数据与核心数据模型完全空白。在ViewController A
中,我以此顺序提出了以下请求:
Api.verifyOtp(email, otp).continueWith { (task) -> Any? in
if task.succeed {
self.apiCallOne()
self.apiCallTwo()
self.apiCallThree()
self.apiCallFour()
self.apiCallFive()
} else {
Hud.hide()
task.showError()
}
return nil
}
现在所有这些调用都是异步进行的。但是,最后一个方法self.apiCallFive()
是推送到ViewController B
的方法。这是电话:
Api.apiCallFive().continueOnSuccessWith { (task) -> Any? in
Hud.hide()
if task.succeed {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewB storyboard.instantiateViewController(withIdentifier: "ViewControllerB" self.navigationController?.pushViewController(viewB, animated: true)
}
我的猜测是,由于所有这些请求都是异步发生的,因此无法保证哪个调用将首先完成。因此,apiCallFive()
在其他人无法完成之前就先推送并加载ViewControllerB。我如何才能使下一个视图在所有任务完成之前不会被加载或推入?
谢谢!
答案 0 :(得分:2)
我也遇到过同样的问题。使用DispatchGroup
进行修复。
代码:
定义为property
let APIGroup = DispatchGroup()
任何API调用开始时,执行以下代码。
APIGroup.enter()
任何API调用完成后,执行以下代码。
downloadGroup.leave()
通知阻止:
APIGroup.notify(queue: DispatchQueue.main) {
print("All APIs called successfully: Perform required operation")
}
无需通过任何计数器或其他变量进行管理。所有任务成功完成后,notify
会自动阻止调用。
这里真正重要的是请输入休假对。你必须的 非常小心,并确保您离开小组。这很容易 在上面的代码中引入错误。假设我们没有离开 返回上方的那个守卫声明中的组。如果 如果API调用失败,或者JSON格式不正确,则groups>条目的数量将与叶子的数量不匹配。这样小组完成 处理程序永远不会被调用。如果您要从 用户界面请求时显示用户界面并显示活动指示器 正在运行,您将永远不会从该方法获得回调,并且您 会继续旋转
答案 1 :(得分:2)
要解决此问题,您需要一种在每次通话结束时得到通知的方式。 最简单的方法是在每个调用中使用完成块。
func apiCall(completion: @escaping () -> Void) {
....
}
将完成代码块添加到api调用后,您的代码块可能如下所示:
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
apiCallOne {
dispatchGroup.leave()
}
dispatchGroup.enter()
apiCallTwo {
dispatchGroup.leave()
}
...
dispatchGroup.enter()
apiCallN {
dispatchGroup.leave()
}
dispatchGroup.wait(timeout: Constants.timeout)
请记住,wait
语句将阻塞您调用它的线程,直到执行所有leave()
语句为止,因此请注意不要以死锁结束。