下面的代码是该任务的粗略草图。查询数据库,它返回结果的集合,对该集合进行循环以搜索特定的属性,如果找到该属性,则立即查询文件存储,并且其异步完成处理程序在循环中返回文件。因为我在for-in循环中处理异步回调,所以我使用DispatchGroup
来管理它。仅当集合中的所有文档都具有someIdentifier
属性时,此设置才有效。如果集合中的一个文档不具有该属性,则调度组从不调用notify()
,而我们陷入了困境。
someDatabaseQuery.retrieveSomeData { (data, error) in
guard let data = data, error == nil else {
return
}
// database has retrieved data, create dispatch group
let dispatchGroup = DispatchGroup()
for document in data { // loop through collection
// check if document has some identifier
guard let someIdentifier = document["someIdentifier"] as? String else {
return
}
dispatchGroup.enter() // identifier found, enter dispatch
// perform async operation inside loop
Filestorage.getSomeFile(forURL: someIdentifier) { (data, error) in
guard let file = data, error == nil else {
return
}
// download the file
dispatchGroup.leave() // leave dispatch
}
}
dispatchGroup.notify(queue: .main) {
// all data grabbed, load table
}
}
答案 0 :(得分:3)
如果您致电leave
,则必须致电enter
。但是,即使您调用了guard
,getSomeFile
完成块中的leave
仍可以阻止对enter
的调用。
一种解决方案是在完成块内使用defer
。在leave
内调用defer
以确保无论您离开该块如何都调用它。
答案 1 :(得分:0)
guard let someIdentifier = document["someIdentifier"] as? String else {
continue // this is the proper control flow statement
}
问题仅仅是选择了错误的控制流语句。当守卫在循环内失败时,return
阻止循环结束,并且从未给调度组提供通知的机会。警卫队中的其他条款应该是continue
,它将控制权保持在循环内(通过使其完成),从而使调度组有机会进行通知。