下载 Firestore 数据时暂停

Pausing while downloading Firestore data

我正在使用 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 将应用程序带到下一个屏幕之前加载所有数据。

我试过:

我已遵循 Ray Wenderlich 关于 DispatchGroups 的教程 (https://www.raywenderlich.com/148515/grand-central-dispatch-tutorial-swift-3-part-2)

我试过这个 Stack Overflow 问题 ()

我已经阅读了DispatchGroup not working in Swift 3 and How do I use DispatchGroup / GCD to execute functions sequentially in swift? and how to use a completion handler to await the completion of a firestore request,但我仍然很困惑。

如何让我的应用程序在继续执行下一个操作之前完全执行这三个功能中的每一个。我什至不关心这三个功能的执行顺序,只要它们在继续之前完全完成即可。

顺便说一句,我的 ViewController 有一个非常漂亮的动画 Activity 指示器视图,可以在这一切发生时娱乐用户。

更新解决方案:

我采纳了布尔数组的建议,以及评论中的 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 才会触发。好像绕了点圈,不过还行。

你可以尝试像这样嵌套调用

func loadingFunction1() {
      self.database.collection("doc").getDocuments() { (querySnapshot, error) in
      // ...get document from Firestore and store it locally

       self.loadingFunction2()
    }
 }

依此类推直到 3

func loadingFunction3() {
      self.database.collection("doc").getDocuments() { (querySnapshot, error) in
      // ...get document from Firestore and store it locally

      self.performSegue(withIdentifier: "goToNextScreen", sender: nil)

    }
 }

嵌套调用会使调用顺序进行,效率不高并且需要更长的时间才能完成。一种更快的方法是让它们 运行ning 像现在一样同时进行,并且当每个完成时,检查它是否是最后一个完成的。

首先,向您的视图控制器添加一组待处理的请求和一种检查它们是否全部完成的方法:

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

这样,您的视图控制器将在所有请求完成后继续,并且它们仍将同时 运行。