我正在使用 Google Firestore 为我的应用用户存储数据。当应用程序加载时,如果用户登录,我想获取他们的数据。我需要访问三个不同的文档,因此我创建了一个 Loading viewController 来调用三个函数,如下所示:
override func viewDidLoad() {
super.viewDidLoad()
loadingFunction1()
loadingFucntion2()
loadingFunction3()
...
self.performSegue(withIdentifier: "goToNextScreen", sender: nil)
}
每个函数看起来都有点像这样:
func loadingFunction1() {
self.database.collection("doc").getDocuments() { (querySnapshot, error) in
...get document from Firestore and store it locally
}
}
我需要在 Segue 将应用程序带到下一个屏幕之前加载所有数据。
我已经尝试过:
- 每个函数的完成处理程序 - 它们各自以正确的顺序执行,但在它们全部完成之前会触发 segue。
- 嵌套完成处理程序 - 将每个函数放入前一个函数的完成处理程序中,segue 在完成之前仍然会触发。
- 将所有三个函数调用放入 DispatchGroup 中,在完成之前仍然会触发。
- 我没有在 ViewController 中执行 DispatchGroup/Queue 操作,而是在包含三个函数的类中的每个函数中执行此操作。在完成之前仍然会触发 Segue。
我遵循了 Ray Wenderlich 关于 DispatchGroups 的教程 ( https://www.raywenderlich.com/148515/grand-central-dispatch-tutorial-swift-3-part-2 )
我已经尝试过这个堆栈溢出问题(iOS - swift 3 - DispatchGroup)
我已阅读DispatchGroup not working in Swift 3和 How do I use DispatchGroup / GCD to execute functions sequentially in swift?和 how to use a completion handler to await the completion of a firestore request我仍然感到困惑。
如何让我的应用程序在继续执行下一个操作之前完全执行这三个功能。我什至不关心这三个功能执行的顺序,只要它们在继续之前完全完成即可。
顺便说一句,我的 ViewController 有一个非常漂亮的动画事件指示器 View ,可以在这一切发生时为用户提供娱乐。
更新解决方案:
我采纳了 Bools 数组的建议,以及评论中的 didSet 想法:
var completedRequests: [Bool] = [false, false, false] {
didSet {
segueWhenAllRequestsAreComplete()
}
}
但是,这还不够。我必须向每个函数添加转义完成处理程序和调度组,如下所示:
func loadingFunction1(completion: @escaping (Bool) -> ()) {
DispatchQueue.global(qos: .userInteractive).async {
let downloadGroup = DispatchGroup()
var success:Bool = false
downloadGroup.enter()
self.database.collection("doc").getDocuments() { (querySnapshot, error) in
if error == nil {
...get document from Firestore and store it locally
success = true
}
downloadGroup.leave()
}
downloadGroup.wait()
DispatchQueue.main.async {
completion(success)
}
}
}
然后像这样调用函数:
DataManager.shared.loadData { success in
self.completedRequests[0] = success
}
现在,终于,在所有三个函数完成之前,segue 不会触发。看起来有点绕,但确实有效。
最佳答案
嵌套调用将使它们连续,这不是很有效并且需要更长的时间才能完成。一种更快的方法是让它们像现在一样同时运行,当每个任务完成时,检查它是否是最后一个完成的。
首先,添加一组待处理的请求以及一种检查它们是否已全部完成到 View Controller 的方法:
var completedRequests: [Bool] = [false, false, false]
func segueWhenAllRequestsCompleted() {
if !completedRequests.contains(false) {
performSegue(withIdentifier: "goToNextScreen", sender: nil)
}
}
然后,在每个加载函数中:
func loadingFunction1() {
completedRequests[0] = false
self.database.collection("doc").getDocuments() { (querySnapshot, error) in
...get document from Firestore and store it locally
self.completedRequests[0] = true
self.segueWhenAllRequestsCompleted()
}
}
func loadingFunction2() {
completedRequests[1] = false
self.database.collection("doc").getDocuments() { (querySnapshot, error) in
...get document from Firestore and store it locally
self.completedRequests[1] = true
self.segueWhenAllRequestsCompleted()
}
}
func loadingFunction3() {
completedRequests[2] = false
self.database.collection("doc").getDocuments() { (querySnapshot, error) in
...get document from Firestore and store it locally
self.completedRequests[2] = true
self.segueWhenAllRequestsCompleted()
}
}
这样,当所有请求完成时,您的 View Controller 将继续执行,并且它们仍会同时运行。
关于ios - 下载 Firestore 数据时暂停,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49417446/