Geofire/Firebase function is executing handler multiple times in swift

有些话、适合烂在心里 提交于 2020-01-06 09:04:47

问题


I have the following function which fetches a list of users using a Geofire then a Firebase query in a nested setup.

I first execute the Geofire query to get the key and I then execute the Firebase query and create the User object that matches the key appending the User to an array which is then passed back via the handler.

The User array is then use in a CollectionView, the problem is that by the time the CollectionView is displayed it only shows one User object.

I have placed some print() lines through out the code for debugging and have found that the function is passing data via handler every time an item is appended and therefore the count of the array by the time is reaches the VC which is displaying the CollectionView is 1.

Moving the following line to outside of the for loop parentheses passes an empty array

How do I update my function so that the handler is only called once and passes a complete array?

handler(self.shuffleArray(array: filteredUsers) as! [User], true)

Here is the function:

    //Fetches all users currently at a Venue location of radius 50 metres
func getUsersAtVenue(forVenueLocation venueLocation: CLLocation, forUid uid: String, handler: @escaping (_ users: [User], _ success: Bool) -> ()){

    print("uid: \(uid)")

    var users = [User]()

    guard let currentLocation = LocationSingleton.sharedInstance.lastLocation else { return}//get current user's (device) location

    let distanceApart = round(10 * (venueLocation.distance(from: currentLocation) / 1000)) / 10 //get distance between currentLocation and venueLocation and convert from Mts to Kms rounding to 2 decimals

    if distanceApart <= 50 { //if distance apart if within 50kms then proceed

        let query = self.GEOFIRE_USERS_LOC.query(at: currentLocation, withRadius: 50)//radius in Kms

        query.observe(.keyEntered) { (key: String!, userLocation: CLLocation!) in

            print(key)

            self.REF_USERS.observeSingleEvent(of: .value, with: { (snapshot) in

                guard let usersSnapshot = snapshot.children.allObjects as? [DataSnapshot] else { return }

                for user in usersSnapshot{

                    let discoverable = user.childSnapshot(forPath: "discoverable").value as! Bool

                    if user.key == key && discoverable == true {

                        let uid = user.key
                        let name = user.childSnapshot(forPath: "name").value as! String
                        let email = user.childSnapshot(forPath: "email").value as! String
                        let profilePictureURL = user.childSnapshot(forPath: "profilePictureURL").value as! String

                        let birthday = user.childSnapshot(forPath: "birthday").value as! String
                        let firstName = user.childSnapshot(forPath: "firstName").value as! String
                        let lastName = user.childSnapshot(forPath: "lastName").value as! String
                        let gender = user.childSnapshot(forPath: "gender").value as! String
                        let discoverable = user.childSnapshot(forPath: "discoverable").value as! Bool
                        let online = user.childSnapshot(forPath: "online").value as! Bool

                        let dictionary: [String : Any] = ["uid": uid, "name": name, "email": email, "profilePictureURL": profilePictureURL, "birthday": birthday, "firstName": firstName, "lastName": lastName, "gender": gender, "discoverable": discoverable, "online": online]

                        let user = User(uid: uid, dictionary: dictionary)

                        users.append(user)

                    }//end if

                }//end for

                //filter out current user from array
                let filteredUsers = users.filter({ (user: User) -> Bool in return !user.uid.contains(uid) })

                print("filteredUsers count: \(filteredUsers.count)")

                //handler passing a shuffled version of the array
                handler(self.shuffleArray(array: filteredUsers) as! [User], true)

            })//end FIR snapshot call

        }//end geoquery


    } else {//if distanace apart is NOT within 50kms then do this
        print("You're too far apart.")
        handler(users, false)
    }



}//end func

Console:

uid: dBQd541pxlRypR7l1WT2utKVxdX2
some("dBQd541pxlRypR7l1WT2utKVxdX5")
some("dBQd541pxlRypR7l1WT2utKVxdX3")
some("dBQd541pxlRypR7l1WT2utKVxdX2")
some("dBQd541pxlRypR7l1WT2utKVxdX4")
filteredUsers count: 1
users count: 1
filteredUsers count: 2
users count: 2
filteredUsers count: 2
users count: 2
filteredUsers count: 3
users count: 3

回答1:


The .keyEntered event is fired for every key that is or comes within range of your geoquery. So initially that means it fires for all keys within range, and from that moment on it will fire whenever a new key comes in range (i.e. if you add a new user in range, or if a user moves to within range).

It sounds like you want to detect when .keyEntered has been called for all initial users. For that you can observe the ready event.

query.observeReadyWithBlock({
    //handler passing a shuffled version of the array
    handler(self.shuffleArray(array: filteredUsers) as! [User], true)
})

If you're not interested in getting updates on new/moving users after the initial query, this is also a great moment to remove your observer by calling removeObserverWithFirebaseHandle or removeAllObservers.

Also see waiting for queries to be 'ready' in the Geofire documentation.



来源:https://stackoverflow.com/questions/50722753/geofire-firebase-function-is-executing-handler-multiple-times-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!