[英]Having trouble using DispatchQueue to wait for data to return from Cloud Firestore in iOS app using Swift
I'm trying to use DispatchQueue to get my code to wait until a query retrieves the results I need from Cloud Firestore before it continues executing, but just haven't been able to get it to work.我正在尝试使用 DispatchQueue 让我的代码等待查询从 Cloud Firestore 检索到我需要的结果,然后再继续执行,但一直无法让它工作。 In the code below I am trying to get it to wait until the data has been retrieved and stored in the zoneMarkerArray, and then print out the result.在下面的代码中,我试图让它等到数据被检索并存储在 zoneMarkerArray 中,然后打印出结果。
I've numbered each line it prints in the order that I want it to happen, and as you'll see in the output it is not waiting for the Firestore result before moving on.我已经按照我希望它发生的顺序对它打印的每一行进行了编号,并且正如您在输出中看到的那样,它不会在继续之前等待 Firestore 结果。
Here is my code:这是我的代码:
let zones = self.db.collection("zones")
let zonesQuery = zones.whereField("start", isGreaterThan: lowerLimit).whereField("start", isLessThan: upperLimit)
print("1. zones Query has been defined")
//pass zonesQuery query to getZoneMarkers function to retrieve the zone markers from Firestore
getZoneMarkers(zonesQuery)
print("6. Now returned from getZoneMarkers")
func getZoneMarkers(_ zonesQuery: Query) -> ([Double]) {
print("2. Entered getZoneMarkers function")
DispatchQueue.global(qos: .userInteractive).async {
zonesQuery.getDocuments() { (snapshot, error) in
if let error = error {
print("Error getting zone markers: \(error)")
} else {
print("3. Successfully Retrieved the zone markers")
var result: Double = 0.0
for document in snapshot!.documents {
print("Retrieved zone marker is \(document["start"]!)")
self.zoneMarkerArray.append(document["start"]! as! Double)
print("4. Looping over zone marker results")
}
}
}
DispatchQueue.main.async {
//I want this the printCompleted function to print the result AFTER the results have been retrieved
self.printCompleted()
}
}
return self.zoneMarkerArray
}
func printCompleted() {
print("5. Looping now completed. Result was \(zoneMarkerArray)")
}
And here is the output that prints out:这是打印出来的输出:
Thanks for the help!谢谢您的帮助!
EDIT: In case anyone else out there is also struggling with this, here's the working code I put together in the end based on the feedback I received.编辑:如果其他人也在为此苦苦挣扎,这是我根据收到的反馈最终汇总的工作代码。 Please feel free to critique if you see how it could be further improved:如果您看到如何进一步改进,请随时提出批评:
let zones = self.db.collection("zones")
let zonesQuery = zones.whereField("start", isGreaterThan: lowerLimit).whereField("start", isLessThan: upperLimit)
print("1. zones Query has been defined")
//pass zonesQuery query to getZoneMarkers function to retrieve the zone markers from Firestore
getZoneMarkers(zonesQuery)
func getZoneMarkers(_ zonesQuery: (Query)) {
print("2. Entered getZoneMarkers function")
zoneMarkerArray.removeAll()
zonesQuery.getDocuments(completion: { (snapshot, error) in
if let error = error {
print("Error getting zone markers: \(error)")
return
}
guard let docs = snapshot?.documents else { return }
print("3. Successfully Retrieved the zone markers")
for document in docs {
self.zoneMarkerArray.append(document["start"]! as! Double)
print("4. Looping over zone marker results")
}
self.completion(zoneMarkerArray: self.zoneMarkerArray)
})
}
func completion(zoneMarkerArray: [Double]) {
print("5. Looping now completed. Result was \(zoneMarkerArray)")
}
Maybe this can help you.也许这可以帮助你。 I have a lot of users, it appends to my Model, and can check when I have all the data und go on with my code:我有很多用户,它附加到我的模型,并且可以检查我何时拥有所有数据并继续使用我的代码:
func allUser (completion: @escaping ([UserModel]) -> Void) {
let dispatchGroup = DispatchGroup()
var model = [UserModel]()
let db = Firestore.firestore()
let docRef = db.collection("users")
dispatchGroup.enter()
docRef.getDocuments { (querySnapshot, err) in
for document in querySnapshot!.documents {
print("disp enter")
let dic = document.data()
model.append(UserModel(dictionary: dic))
}
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
completion(model)
print("completion")
}
} }
From the question, it doesn't appear like any DispatchQueue's are needed.从问题来看,似乎不需要任何 DispatchQueue。 Firestore asynchronous so data is only valid inside the closures following the firebase function. Firestore 是异步的,因此数据仅在 firebase 函数之后的闭包内有效。 Also, UI calls are handled on the main thread whereas networking is on the background thread.此外,UI 调用在主线程上处理,而网络在后台线程上处理。
If you want to wait for all of the data to be loaded from Firestore, that would be done within the closure following the Firestore call.如果您想等待从 Firestore 加载所有数据,这将在 Firestore 调用之后的闭包内完成。 For example, suppose we have a zones collection with documents that store start and stop indicators例如,假设我们有一个区域集合,其中包含存储开始和停止指示符的文档
zones
zone_0
start: 1
stop: 3
zone_1
start: 7
stop: 9
For this example, we'll be storing the start and stop for each zone in a class array of tuples对于这个例子,我们将在一个元组类数组中存储每个区域的开始和停止
var tupleArray = [(Int, Int)]()
and the code to read in the zones, populate the tupleArray and then do the 'next step' - printing them in this case.以及在区域中读取的代码,填充 tupleArray 然后执行“下一步” - 在这种情况下打印它们。
func readZoneMarkers() {
let zonesQuery = self.db.collection("zones")
zonesQuery.getDocuments(completion: { documentSnapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = documentSnapshot?.documents else { return }
for doc in docs {
let start = doc.get("start") as? Int ?? 0
let end = doc.get("end") as? Int ?? 0
let t = (start, end)
self.tupleArray.append(t)
}
//reload your tableView or collectionView here,
// or proceed to whatever the next step is
self.tupleArray.forEach { print( $0.0, $0.1) }
})
}
and the output和输出
1 3
7 9
Because of the asynchronous nature of Firebase, you can't 'return' from a closure, but you can leverage a completion handler if needed to pass the data 'back' from the closure.由于 Firebase 的异步特性,您不能从闭包“返回”,但如果需要,您可以利用完成处理程序将数据从闭包“返回”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.