Reputation: 1708
For some reason when I run the following method, the first query runs after the method completes. I tried using a dispatch block in order to force the query to run first, but the query never runs at all then and the app simply freezes. Let me know if you know what is wrong.
Method without dispatch group:
func loadConversations() {
let ref = FIRDatabase.database().reference()
let convoRef = ref.child("users").child(FIRAuth.auth()!.currentUser!.uid).child("conversations")
var conversationID = [String]()
print(1)
convoRef.queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
let enumerator = snapshot.children
print(2)
while let rest = enumerator.nextObject() as? FIRDataSnapshot {
print(3)
if let id = rest.value as? String{
conversationID.append(id)
print(id)
}
}
})
print(4)
print("size: \(conversationID.count)")
for id in conversationID {
print(5)
ref.child("conversations").queryEqual(toValue: id).observeSingleEvent(of: .value, with: { (snapshot) in
print(6)
if let convo = snapshot.value as? [String : AnyObject] {
print(7)
let conversation = Conversation()
conversation.conversationID = id
conversation.name = "Temporary test name"
self.Conversations.append(conversation)
}
})
ref.removeAllObservers()
}
print(8)
self.conversationTableView.reloadData()
ref.removeAllObservers()
}
This prints:
1
4
size: 0
8
2
3
-KZyMMzXmkQC_OF0T08_
With the dispatch group:
func loadConversations() {
let dispatchGroup = DispatchGroup()
let ref = FIRDatabase.database().reference()
let convoRef = ref.child("users").child(FIRAuth.auth()!.currentUser!.uid).child("conversations")
var conversationID = [String]()
print(1)
dispatchGroup.enter()
convoRef.queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
let enumerator = snapshot.children
print(2)
while let rest = enumerator.nextObject() as? FIRDataSnapshot {
print(3)
if let id = rest.value as? String{
conversationID.append(id)
print(id)
dispatchGroup.leave()
}
}
})
print(4)
dispatchGroup.wait()
print("size: \(conversationID.count)")
for id in conversationID {
print(5)
ref.child("conversations").queryEqual(toValue: id).observeSingleEvent(of: .value, with: { (snapshot) in
print(6)
if let convo = snapshot.value as? [String : AnyObject] {
print(7)
let conversation = Conversation()
conversation.conversationID = id
conversation.name = "Temporary test name"
self.Conversations.append(conversation)
}
})
}
print(8)
self.conversationTableView.reloadData()
ref.removeAllObservers()
}
This prints
1
4
but then it just freezes and waits. The query never runs.
I am not sure why the query just does not appear to be entered. When the query is entered, it works perfectly fine, but it is entered too late. Any help is greatly appreciated. Thanks!
Upvotes: 1
Views: 265
Reputation: 4232
This is simply because Firebase queries are executed on a background thread as it is essentially a network call. Hence the response comes after your method completes, otherwise the UI will be blocked until a response comes from Firebase
You need to write a closure inside your query response to execute a block of code as soon as you get the response.
func loadConversations(completion:@escaping (Array<String>) -> Void) -> Void {
let ref = FIRDatabase.database().reference()
let convoRef = ref.child("users").child(FIRAuth.auth()!.currentUser!.uid).child("conversations")
var conversationID = [String]()
print(1)
convoRef.queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
let enumerator = snapshot.children
print(2)
while let rest = enumerator.nextObject() as? FIRDataSnapshot {
print(3)
if let id = rest.value as? String{
conversationID.append(id)
print(id)
}
}
completion(conversationID)
})
}
This will send your call back to wherever it was called from and inside
loadConversations { (array) in
//do something with this value and execute next query
}
Upvotes: 2