【发布时间】:2021-03-26 16:27:58
【问题描述】:
我正在尝试从 FireStore 数据库中获取文档。在继续执行我的功能之前,我需要加载这些文档。以下是参考代码:
调用 FireStore 服务函数的视图控制器:
let service = FirestoreServices()
service.get(cottage: "test123456789") { model in
nextViewController.cottageModel = model!
self.present(nextViewController, animated:true, completion:nil)
}
正在调用的 FireStore 服务方法:
func get(cottage: String, completionHandler: @escaping (CottageTrip?) -> ()) {
//get a reference to the firestore
let db = Firestore.firestore()
//get the references to the collections
let cottageRef = db.collection("cottages").document(cottage)
//get the fields from the initial document and load them into the cottage model
cottageRef.getDocument { (document, error) in
if let document = document, document.exists {
//create the cottage model to return
let cottageModel: CottageTrip = CottageTrip()
//get the subcollections of this document
let attendeesCollection = cottageRef.collection("attendees")
//other collections
//here I get all info from initial document and store it in the model
let group = DispatchGroup()
print("here")
group.enter()
//get the attendees
DispatchQueue.global(qos: .userInitiated).async {
attendeesCollection.getDocuments() { (querySnapshot, err) in
print("here2")
if let err = err {
print("Error getting documents: \(err)")
} else {
//get data
}
group.leave()
}
}
print("after async call")
//wait here until the attendees list is built
group.wait()
print("after wait")
//create the cars
carsCollection.getDocuments() { (querySnapshot, err) in
print("in car collection get doc call")
if let err = err {
print("Error getting documents: \(err)")
} else {
//get car data
}
}
}
//this is where she should block until all previous get document operations complete
completionHandler(cottageModel)
} else {
print("Document does not exist")
completionHandler(nil)
}
}
}
我意识到print("here2") 永远不会打印,所以它似乎阻塞在group.wait() 上。我需要使用group.wait() 而不是通知,因为我需要此函数仅在加载参加者集合后才能访问子集合和文档,因为我需要这些值用于子集合和文档。我在网上阅读了很多答案,大多数人在这种情况下使用group.wait(),但由于某种原因,如果不锁定和冻结应用程序,我无法让它为我工作。
【问题讨论】:
-
你调用 wait() 它会阻塞你的主线程,直到 leave() 被调用。但它永远不会被调用,因为 getDocuments() 的完成闭包也需要在主线程上运行。你有一个僵局。
-
我看不出使用基于您提供的代码的调度组有任何意义,因为似乎为创建山寨模型而执行的所有任务都已经是串行的。首先获取文档,然后查询子集合,然后执行
x,然后执行y。所有这些都已经是串行的,所以只需像你一样嵌套它们,如果在任何时候出现故障(如缺少文档或网络错误),请在完成处理程序中返回nil并继续。 -
@bsod 这两个
getDocuments调用是异步的,所以如果你想让它们同时运行,你需要让组知道它们什么时候完成。但是,如果您需要一个结果用于另一个,那么您是正确的,您可以通过嵌套它们一个接一个地运行,从而消除对组的需要。
标签: ios swift firebase google-cloud-firestore grand-central-dispatch