在访问核心数据模型之前,如何确保已进行所有网络调用?

时间:2019-04-19 09:28:35

标签: ios swift

我连续进行多个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。我如何才能使下一个视图在所有任务完成之前不会被加载或推入?

谢谢!

2 个答案:

答案 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>条目的数量将与叶子的数量不匹配。这样小组完成   处理程序永远不会被调用。如果您要从   用户界面请求时显示用户界面并显示活动指示器   正在运行,您将永远不会从该方法获得回调,并且您   会继续旋转

Apple documents

答案 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()语句为止,因此请注意不要以死锁结束。