我正在使用Google Firestore为我的应用程序的用户存储数据。应用加载后,如果用户已登录,我想获取他们的数据。我需要访问三个不同的文档,因此我创建了一个Loading视图控制器,它调用如下三个函数:

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 3How 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有一个非常漂亮的动画活动指示器视图,可以在这一切发生时为用户带来娱乐。

解决方案更新:

我采纳了一系列的Bools建议,并在评论中使用了didSet的想法:

var completedRequests: [Bool] = [false, false, false] {

    didSet {
        segueWhenAllRequestsAreComplete()
    }
}


但是,这还不够。我必须向每个函数添加转义完成处理程序和dispatchGroup,如下所示:

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才最终触发。似乎有一些回合,但它可行。

最佳答案

嵌套调用会使它们顺序执行,这不是很有效,并且需要更长的时间才能完成。一种更快的方法是使它们像现在一样并发运行,并在每个完成时检查是否最后一个要完成。

首先,将一系列待处理的请求以及一种检查请求是否已完成的方法添加到视图控制器:

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


这样,您的视图控制器将在所有请求均已完成并且仍将同时运行时发出请求。

关于ios - 下载Firestore数据时暂停,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49417446/

10-12 14:35