How to reload data after all Firebase calls finish

2020-06-06 05:17发布

问题:

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
}) 

回答1:

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.

  1. First of all we create a group DispatchGroup(). This value will keep track of the number of pending blocks.

    let group = DispatchGroup()
    
  2. Then before starting a new asynchronous call we tell the group there is a new pending block.

    group.enter()
    
  3. Inside the callback closure we tell the group that one block has finished its work.

    group.leave()
    
  4. 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")
    }
    


回答2:

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;
            }
});