I'm using Firebase (Swift) to read a list of group ids that the user belongs to then looping over the ids to get more info about the groups. Something similar to this (pseudo code):
// List the names of all Mary's groups
var ref = new Firebase("https://docs-examples.firebaseio.com/web/org");
// fetch a list of Mary's groups
ref.child("users/mchen/groups").on('child_added', function(snapshot) {
// for each group, fetch the name and print it
String groupKey = snapshot.key();
ref.child("groups/" + groupKey + "/name").once('value', function(snapshot) {
System.out.println("Mary is a member of this group: " + snapshot.val());
});
});
How do I know that all Firebase observeSingleEvent
has done executing so I could reload the data in my collection view.
Edit:
After doing more research, this looks very similar to this question. I could use dispatch_group
or Bolts framework
Edit 2:
Thanks to @appzYourLife for his answer. I also was able to solve it using RxSwift
. I simply wrapped the Firebase calls with observers and saved them in an array then called
Observable.zip(observables, { _ in }).subscribe(onCompleted: {
self.contentView.collection.reloadData() // do something here
})
If you want to be notified when all the firebase calls have been completed you can use this code
let ref = FIRDatabase.database().reference()
ref.child("users/mchen/groups").observeSingleEvent(of: .value, with: { snapshot in
let groupKeys = snapshot.children.flatMap { $0 as? FIRDataSnapshot }.map { $0.key }
// This group will keep track of the number of blocks still pending
let group = DispatchGroup()
for groupKey in groupKeys {
group.enter()
ref.child("groups").child(groupKey).child("name").observeSingleEvent(of: .value, with: { snapshot in
print("Mary is a member of this group: \(snapshot.value)")
group.leave()
})
}
// We ask to be notified when every block left the group
group.notify(queue: .main) {
print("All callbacks are completed")
}
})
How does it work?
There are 4 main instructions involved.
First of all we create a group DispatchGroup()
. This value will keep track of the number of pending blocks.
let group = DispatchGroup()
Then before starting a new asynchronous call we tell the group there is a new pending block.
group.enter()
Inside the callback closure we tell the group that one block has finished its work.
group.leave()
We tell the block to run a closure when the number of blocks into the group does become zero.
group.notify(queue: .main) {
print("All callbacks are completed")
}
You have the list of groups, so you can store the count in one Int object. Lets say totalCount.
Then take another object.
Lets say counter.
Then in each completion handler .
After the print statement
ref.child("groups/" + groupKey + "/name").once('value', function(snapshot)
{
System.out.println("Mary is a member of this group: " + snapshot.val());
if counter == count
{
collectionView.reload();
}
else
{
counter += 1;
}
});