我正在为图书馆创建一个应用程序。我试图获取用户从 Firebase checkout 的所有书籍,但我尝试使该函数与 DispatchGroup 异步似乎不起作用。我怀疑这是因为函数内部发现了 for-in 循环。
func fetchHistory() {
if items.count > 0 {
items.removeAll()
}
let myGroup = DispatchGroup()
myGroup.enter()
var itemNames = [String]() // this holds the names of the child values of /users/uid/items/ <-- located in Firebase Database
guard let uid = fAuth.currentUser?.uid else {return}
fData.child("users").child(uid).child("items").observe(.value, with: { snapshot in
// make sure there is at least ONE item in the history
if snapshot.childrenCount > 0 {
let values = snapshot.value as! NSDictionary
for i in values.allKeys {
itemNames.append(i as! String)
}
print(itemNames)
let uid = fAuth.currentUser!.uid // get the UID of the user
for item in itemNames {
fData.child("users").child(uid).child("items").child(item).observe(.value, with: { snapshot in
let values = snapshot.value as! NSDictionary
let bookTitle = values["title"] as! String
print(bookTitle)
let bookAuthor = values["author"] as! String
print(bookAuthor)
let bookCoverUrl = values["coverUrl"] as! String
print(bookCoverUrl)
let bookStatus = values["status"] as! String
print(bookStatus)
let bookDueDate = values["dueDate"] as! String
print(bookDueDate)
let book = Book(name: bookTitle, author: bookAuthor, coverUrl: bookCoverUrl, status: bookStatus, dueDate: bookDueDate)
self.items.append(book)
})
}
self.booksTable.isHidden = false
} else {
self.booksTable.isHidden = true
}
})
myGroup.leave()
myGroup.notify(queue: DispatchQueue.main, execute: {
self.booksTable.reloadData()
print("Reloading table")
})
}
这是 print() 语句的输出:
########0
Reloading table
["78DFB90A-DE5B-47DE-ADCA-2DAB9D43B9C8"]
Mockingjay (The Hunger Games, #3)
Suzanne Collins
https://images.gr-assets.com/books/1358275419s/7260188.jpg
Checked
Replace
输出的前两行应该在其他所有内容打印之后打印。我真的需要一些帮助,我已经被困在这个问题上几个小时了。谢谢!
编辑: 根据要求,这是我的 Firebase 结构:
users:
meZGWn5vhzXpk5Gsh92NhSasUPx2:
ID: "12345"
firstname: "Faraaz"
items:
78DFB90A-DE5B-47DE-ADCA-2DAB9D43B9C8
author: "Suzanne Collins"
coverUrl: "https://images.gr assets.com/books/1358275419s/..."
dueDate: "Date"
status: "Checked"
title: "Mockingjay (The Hunger Games, #3)"
type: "regular"
最佳答案
几个问题:
该模式是
leave
必须在异步调用的完成处理程序内调用。您希望这是闭包内执行的最后一件事,因此您可以将其添加为完成处理程序闭包内的最后一行。或者我更喜欢使用
defer
子句,这样您不仅知道它将是闭包中执行的最后一件事,而且还:- 即使您稍后在闭包中添加任何“提前退出”,也要确保您
离开
;和 enter
和leave
调用在代码中直观地显示在彼此旁边,使您不必在闭包的底部进行视觉搜索以确保它被正确调用。
- 即使您稍后在闭包中添加任何“提前退出”,也要确保您
如果您想在
for
循环中等待异步调用,也必须将其添加到此处。这是一个非常小的问题,但您可能不希望在成功解包
uid
之前创建组。如果您可以返回
并且不执行任何异步代码,为什么要创建DispatchGroup
?
因此,也许:
func fetchHistory() {
if items.count > 0 {
items.removeAll()
}
var itemNames = [String]()
guard let uid = fAuth.currentUser?.uid else {return}
let group = DispatchGroup()
group.enter()
fData.child("users").child(uid).child("items").observe(.value, with: { snapshot in
defer { group.leave() } // in case you add any early exits, this will safely capture
if snapshot.childrenCount > 0 {
...
for item in itemNames {
group.enter() // also enter before we do this secondary async call
fData.child("users").child(uid).child("items").child(item).observe(.value, with: { snapshot in
defer { group.leave() } // and, again, defer the `leave`
...
})
}
...
} else {
...
}
})
group.notify(queue: .main) {
self.booksTable.reloadData()
print("Reloading table")
}
}
关于swift - 如何在 Swift 中使带有循环的函数异步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55461025/