Я разрабатываю приложение для чата iOS, которое использует базу данных Firebase Realtime для хранения сообщений. У меня есть функция, которая вызывается при загрузке экрана домашнего чата. Эта функция загружает имя получателя, последнее сообщение, метку времени и профиль pi c. Я использовал DispatchGroup для синхронизации c всех вызовов. Сначала я думал, что это работает, но когда я отправляю новое сообщение (каким-либо образом обновляю БД), приложение вылетает. Я полагаю, что это потому, что закрытие наблюдения вызывается снова, и между вызовами входа / выхода есть дисбаланс. Я не могу придумать, как заставить это работать с 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 ед. Поэтому здесь у меня есть массив всех чатов.
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. Все еще не повезло.