1

In my Firebase Realtime Database, I have a node labelled "groups" and this is how I constructed it:

Groups Node - Firebase

Underneath the "users" above, I'm trying to use those userIds to reference the data within each user. This is how I constructed each "users" node I'm trying to reference:

Users Node - Firebase

In the below code snippet, I get the userIds from a snapshot of the groups' users child node. And then I run a for-in loop on those userIds to access the information in the "users" node.

The print("This should be the individual userId: ", userId) statement prints out each userId correctly. And the userRef.observeSingleEvent(of: .value, with: { (snapshot) in gets called the first time the for-in loop is called, but it's almost like it's ignored. The app crashes because the user array comes up empty at the end. However, a ridiculous amount of empty users show up in the array (when looking at the Variables View in the Debug Area). So, i feel like I'm running some form of a redundant loop or something.

guard let groupChatPartnerId = message.chatPartnerId() else {
    return
}

var users: [User]?

let ref = Database.database().reference().child("groups").child(groupChatPartnerId)
ref.observeSingleEvent(of: .value, with: { (snapshot) in

    let groupId = snapshot.key

    let groupName = snapshot.childSnapshot(forPath: "groupName").value as! String

    let userIdDictionary = snapshot.childSnapshot(forPath: "users").value as! Dictionary<String,AnyObject>
    let userIds = Array(userIdDictionary.keys)
    print("userIds: ", userIds)



    for userId in userIds {
        print("This should be the individual userId: ", userId)
        let userRef = Database.database().reference().child("users").child(userId)
        userRef.observeSingleEvent(of: .value, with: { (snapshot) in
            print("This is the snapshot: ", snapshot)
            let email: String = snapshot.childSnapshot(forPath: "email").value as! String
            print("user's email: ", email)
            let uid = snapshot.key
            let username = snapshot.childSnapshot(forPath: "username").value as! String
            let profileImageUrl = snapshot.childSnapshot(forPath: "profileImageUrl").value as! String

            let user = User(uid: uid, userUsername: username, userProfileImageUrl: profileImageUrl, userEmail: email)

            users?.append(user)
            print("user to append to users: ", user)

        }, withCancel: nil)

    }

    print("users :", users)

    let group = Group(groupId: groupId, groupName: groupName, users: users!)
    self.showChatControllerForGroup(group: group)

}, withCancel: nil)

Let me know if you need any other information. Thanks in advance!

1 Answer 1

1

All data is loaded from Firebase asynchronously By the time your print users, none of the userRef.observeSingleEvent has completed yet. So the code to print all users must be inside the completion handle of userRef.observeSingleEvent and must only run once all users have been loaded.

A simple way to do that is to compare the length of users with the length of userIds. If they're the same, you've loaded all users:

for userId in userIds {
    print("This should be the individual userId: ", userId)
    let userRef = Database.database().reference().child("users").child(userId)
    userRef.observeSingleEvent(of: .value, with: { (snapshot) in
        print("This is the snapshot: ", snapshot)
        let email: String = snapshot.childSnapshot(forPath: "email").value as! String
        print("user's email: ", email)
        let uid = snapshot.key
        let username = snapshot.childSnapshot(forPath: "username").value as! String
        let profileImageUrl = snapshot.childSnapshot(forPath: "profileImageUrl").value as! String

        let user = User(uid: uid, userUsername: username, userProfileImageUrl: profileImageUrl, userEmail: email)

        users?.append(user)
        print("user to append to users: ", user)

        if userIds.count == users.count {
            print("users :", users)
        }
    }, withCancel: nil)

}
Sign up to request clarification or add additional context in comments.

5 Comments

the problem I'm having is that it seems like userRef.observeSingleEvent isn't being called because print("This is the snapshot: ", snapshot) and all the other print statements in the compeltion handle of userRef.observeSingleEvent aren't being printed.
i was thinking that since the "users" values in "groups" isn't changed, that's why it isn't being called. At least that's what the Firebase documentation led me to believe
I'm confused. In your question you said that userRef.observeSingleEvent does get called, and my answer doesn't change anything about that. All I've done is move the printing of the array into that callback, and make it dependent on the number of users that has been loaded.
so, when I put a breakpoint at userRef.observeSingleEvent, the breakpoint stops on that line but nothing inside it ever gets called. sorry about the confusion! Does this make more sense?
And this doesn't make sense to me because whenever I've tried to read info from the Firebase Database, I've gotten a snapshot with observeSingleEvent and then gotten the data from that. But here the info within the observeSingleEvent's completion handle isn't even being called

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.