简体   繁体   English

下载Firestore数据时暂停

[英]Pausing while downloading Firestore data

I am using Google Firestore to store data for my App's users. 我正在使用Google Firestore为我的应用程序的用户存储数据。 When the app loads, if a user is logged in, I want to get their data. 应用加载后,如果用户已登录,我想获取他们的数据。 I need to access three different documents, so I have created a Loading viewController that calls three functions like this: 我需要访问三个不同的文档,因此我创建了一个Loading视图控制器,它调用如下三个函数:

override func viewDidLoad() {
    super.viewDidLoad()
    loadingFunction1()
    loadingFucntion2()
    loadingFunction3()
    ...
    self.performSegue(withIdentifier: "goToNextScreen", sender: nil)
}

Each function looks a little like this: 每个函数看起来都像这样:

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

I need to load all of the data before the segue takes the app to the next screen. 我需要先加载所有数据,然后segue才能将应用程序带到下一个屏幕。

I have tried: 我努力了:

  • completion handlers for each function - they each execute in the correct order, but the segue fires before they are all done. 每个函数的完成处理程序-它们各自以正确的顺序执行,但是segue在它们全部完成之前就会触发。
  • nesting completion handlers - putting each function in the completion handler for the prior function, still the segue fires before they are done. 嵌套完成处理程序-将每个函数放在先前功能的完成处理程序中,仍然会在完成之前触发segue。
  • putting all three function calls in a DispatchGroup, still fires before they are done. 将所有三个函数调用放入DispatchGroup中,仍会在完成之前触发。
  • instead of doing the DispatchGroup/Queue thing in the ViewController, I have done it inside each function in the class that holds the three functions. 我没有在ViewController中执行DispatchGroup / Queue事情,而是在包含三个函数的类的每个函数中完成了它。 Still fires the segue before they are done. 在完成之前,仍然会开火。

I have followed Ray Wenderlich's tutorial on DispatchGroups ( https://www.raywenderlich.com/148515/grand-central-dispatch-tutorial-swift-3-part-2 ) 我遵循了Ray Wenderlich的DispatchGroups教程( https://www.raywenderlich.com/148515/grand-central-dispatch-tutorial-swift-3-part-2

I have tried this Stack Overflow question ( iOS - swift 3 - DispatchGroup ) 我已经试过这个Stack Overflow问题( iOS-swift 3-DispatchGroup

I have read DispatchGroup not working in Swift 3 and How do I use DispatchGroup / GCD to execute functions sequentially in swift? 我已阅读DispatchGroup在Swift 3中不起作用, 如何使用DispatchGroup / GCD在swift中按顺序执行功能? and how to use a completion handler to await the completion of a firestore request and I am still stumped. 以及如何使用完成处理程序来等待Firestore请求的完成,我仍然感到困惑。

How do I make my app execute each of the three functions completely before moving on to the next action. 在继续下一步操作之前,如何使我的应用完全执行这三个功能。 I don't even care what order the three functions are carried out, just so long as they are completely done before moving on. 我什至不在乎这三个功能的执行顺序,只要在继续进行之前将它们完全完成即可。

BTW, my ViewController has a very nice animated Activity Indicator View to entertain the user while this is all happening. 顺便说一句,我的ViewController有一个非常漂亮的动画“活动指示器视图”,可以在发生这种情况时娱乐用户。

UPDATE with Solution: 解决方案更新:

I adopted the array of Bools suggestion, with the didSet idea from the comments: 我采用了一系列的Bools建议,并在注释中使用了didSet的想法:

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

    didSet {
        segueWhenAllRequestsAreComplete()
    }
}

However, that wasn't enough. 但是,这还不够。 I had to add both an escaping completion handler and a dispatchGroup to each function, like this: 我必须向每个函数添加转义完成处理程序和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)
        }
    }   
}

and then call the functions like this: 然后调用如下函数:

DataManager.shared.loadData { success in
    self.completedRequests[0] = success
}

So now, at long last, the segue does not fire until all three functions are finished. 因此,现在,直到全部三个功能都完成后,segue才会启动。 Seems a little round about, but it works. 似乎有一些回合,但它可行。

You can try to nest calls like this 您可以尝试像这样嵌套通话

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

       self.loadingFunction2()
    }
 }

and so on until 3 直到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)

    }
 }

Nesting the calls will make them sequential, which is not very efficient and will take much longer to complete. 嵌套调用将使它们按顺序进行,这不是很有效,将需要更长的时间才能完成。 A quicker way would be to keep them running concurrently as you have at the moment, and when each one completes, check if it is the last one to complete. 一种更快的方法是使它们像现在一样并发运行,并在每个完成时检查是否最后一个要完成。

Firstly, add an array of requests that are pending and a way to check they are all completed to your view controller: 首先,将一系列待处理的请求以及一种检查请求是否已完成的方法添加到视图控制器:

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

func segueWhenAllRequestsCompleted() {
    if !completedRequests.contains(false) {
        performSegue(withIdentifier: "goToNextScreen", sender: nil)
    }
}

Then, in each of your loading functions: 然后,在每个加载函数中:

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

This way, your view controller will segue when all the requests have completed and they will still run at the same time. 这样,您的视图控制器将在所有请求完成后自动选择并继续运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM