[英]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: 我努力了:
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.