[英]Error in handling a series of async functions using dispatchGroup in Swift
[英]DispatchGroup with async functions in a Firebase Realtime DB observe method in Swift
我正在开发一个使用 Firebase 实时数据库来存储消息的 iOS 聊天应用程序。 我有一个在加载主聊天屏幕时调用的函数。 此函数加载收件人姓名、最后一条消息、时间戳和个人资料图片。 我使用 DispatchGroup 来同步所有呼叫。 起初,我认为它有效,但是当我发送新消息(以任何方式更新数据库)时,应用程序崩溃了。 我相信这是因为再次调用了observe 闭包,并且进入/离开调用之间存在不平衡。 我想不出一种方法让它与 DispatchGroup 一起工作。 有没有办法来解决这个问题? 或者有比 DispatchGroup 更好的选择吗?
这是 firebase 观察者的主要功能:
func getAllChatsForCurrentUser(completion: @escaping (_ chats: [Chat], _ error: Error?) -> Void) {
var chats = [Chat]()
let group = DispatchGroup()
let currentUserUID = Auth.auth().currentUser!.uid
let chatRef = Database.database().reference(withPath: "chats")
group.enter()
chatRef.observe(.value) { (snapshot) in
var childrenArray = [String]()
let children = snapshot.children
while let rest = children.nextObject() as? DataSnapshot {
childrenArray.append(rest.key) //1
}
for child in childrenArray {
if child.contains(currentUserUID) { //2
let otherUserUID = child.replacingOccurrences(of: currentUserUID, with: "")
group.enter()
self.getChatInfo(uid: otherUserUID, chatID: child) { (chat, err) in
chats.append(chat)
group.leave()
}
}
}
group.leave()
}
group.notify(queue: .main) {
completion(chats, nil)
}
}
1 - 对于聊天名称,我使用了 2 个 uid 的组合。 所以在这里我有一个所有聊天的数组。
2 - 如果聊天名称包含当前用户的 uid - 我正在使用它。 字符串另一部分中的收件人 uid。
getChatInfo 函数如下:
func getChatInfo(uid: String, chatID: String, completion: @escaping (_ chat: Chat, _ error: Error?) -> Void) {
let miniGroup = DispatchGroup()
var newChat = Chat()
newChat.otherUserUid = uid
miniGroup.enter()
self.getUserProfileFromUID(uid: uid) { (user, error) in
newChat.name = user.name
newChat.profilePic = user.photoURL
miniGroup.leave()
}
miniGroup.enter()
self.getLastMessageAndTimeForChat(chatID: chatID) { (message, time, error) in
newChat.lastMessage = message
newChat.lastMessageTime = time
miniGroup.leave()
}
miniGroup.notify(queue: .main) {
completion(newChat, nil)
}
}
我知道这可能是构建数据和调用函数的一种糟糕方式。 至少我被告知是这样,没有理由。 被这个问题困扰了近一个星期,任何信息将不胜感激。
更新 1尝试将leave()
调用包装在defer {}
,并尝试使用 NSOperations 而不是 DispatchGroup。 仍然没有运气。
所以我通过使用带有开始处理程序的完成处理程序来解决这个问题。
getChatsWithBeginAndComplete(beginHandler: {
self.group.enter()
self.group.notify(queue: .main) {
print("done")
self.tableView.reloadData()
}
}) {
self.group.leave()
}
和功能:
func getChatsWithBeginAndComplete(beginHandler: @escaping () -> (), completionHandler: @escaping () -> ()) {
allChatsHandle = allChatsRef.observe(.value) { (snapshot) in
let bigGroup = DispatchGroup()
beginHandler()
var childrenArray = [String]()
let children = snapshot.children
while let rest = children.nextObject() as? DataSnapshot {
childrenArray.append(rest.key)
}
for chatID in childrenArray {
if chatID.contains(currentUserUID) {
bigGroup.enter()
let funcGroup = DispatchGroup()
//Do more async stuff in the funcGroup
funcGroup.notify(queue: .main) {
self.chats.append(chat)
bigGroup.leave()
}
}
}
bigGroup.notify(queue: .main) {
completionHandler()
}
}
}
所以这里所有的 group.enter 和 group.leave 调用都是平衡的,因为它们是从完成/开始处理程序或从 firebase 观察者内部调用的。 我不认为这是处理这个问题的最好方法,但这绝对是一种方法。 如果有人知道更好的解决方案 - 请告诉我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.