3

How can I execute some code after fetching all childadded from Firebase in Swift 5?

I've tried using DispatchGroup and observe .value, but none of them worked efficiently.

let dispatchGroup = DispachGroup()

ref.child("path").observe(.childAdded, with: { (snapshot) in
     self.dispatchGroup.enter()
     //store snapshot data into an object
     self.dispatchGroup.leave()
})

dispatchGroup.notify(queue: .main) {
    //code to execute after all children are fetched
}

In this case, the code will be executed before fetching the data.

How can I execute code when only the callback block reaches the last child?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Difeng Chen
  • 155
  • 1
  • 1
  • 9

2 Answers2

5

One option is to leverage that Firebase .value functions are called after .childAdded functions.

What this means is that .childAdded will iterate over all childNodes and then after the last childNode is read, any .value functions will be called.

Suppose we want to iterate over all users in a users node, print their name and after the last user name is printed, output a message that all users were read in.

Starting with a simple structure

users
   uid_0
      name: "Jim"
   uid_1
      name: "Spock"
   uid_2
      name: "Bones"

and then the code that reads the users in, one at a time, prints their name and then outputs to console when all names have been read

var initialRead = true

func readTheUsers() {
    let usersRef = self.ref.child("users")

    usersRef.observe(.childAdded, with: { snapshot in
        let userName = snapshot.childSnapshot(forPath: "name").value as? String ?? "no name"
        print(userName)

        if self.initialRead == false {
            print("a new user was added")
        }
    })

    usersRef.observeSingleEvent(of: .value, with: { snapshot in
        print("--inital load has completed and the last user was read--")
        self.initialRead = false
    })
}

and the output

Jim
Spock
Bones
--inital load has completed and the last user was read--

Note this will leave an observer on the users node so if a new user is added it will print their name as well.

Note Note: self.ref points to my root firebase reference.

Jay
  • 34,438
  • 18
  • 52
  • 81
  • wouldn't both of these happen in tandem? What reason does the second observeSingleEvent have to wait for the first observe event. I understand that .value fires after .childAdded is finished but I don't understand how since they are 2 completely different operations, how does one know about the other. The only thing that comes to mind is that they both use the same usersRef (does that master ref determine the order) but it's still not clear what the wait is for. – Lance Samaria Jun 17 '20 at 00:08
  • @LanceSamaria They do not occur in tandem - which is the whole bases for the process. .value events are always called after .childxxx events. You can read some about that here [Event Guarantees](https://firebase.google.com/docs/database/admin/retrieve-data#section-event-guarantees) - it's in the admin section but applies across the board. – Jay Jun 17 '20 at 16:36
  • I understand that part, it’s just odd to me that 2 different processes that have nothing to do with each other still know about each. It’s just strange. Thanks for the link – Lance Samaria Jun 17 '20 at 16:38
  • "One option is to leverage that Firebase .value functions are called after .childAdded functions." @Jay best discovery of the day! Thanks! – fabdurso Nov 07 '20 at 17:01
1

When you're listening to .childAdded, there is no way when your code is getting called for the last child. So if you must treat the last child different, listen for .value and loop over the children as shown here.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807