【问题标题】:Pausing while downloading Firestore data下载 Firestore 数据时暂停
【发布时间】:2018-03-21 22:18:13
【问题描述】:

我正在使用 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)

我试过这个 Stack Overflow 问题 (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 数组的建议,以及来自 cmets 的 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 不会触发。看起来有点绕,但确实有效。

【问题讨论】:

    标签: ios swift grand-central-dispatch google-cloud-firestore completionhandler


    【解决方案1】:

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

    首先,向视图控制器添加一组待处理的请求以及检查它们是否已完成的方法:

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

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

    【讨论】:

    • 如果这将是另一种解决方案,最好使用 didSet 而不是编写 segueWhenAllRequestsCompleted everyWhere
    【解决方案2】:

    你可以尝试这样嵌套调用

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

    【讨论】:

      猜你喜欢
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      • 1970-01-01
      相关资源
      最近更新 更多