Geofire/Firebase函数正在迅速执行处理程序多次 [英] Geofire/Firebase function is executing handler multiple times in swift

查看:43
本文介绍了Geofire/Firebase函数正在迅速执行处理程序多次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我具有以下功能,该功能使用Geofire以及嵌套设置中的Firebase查询来获取用户列表.

我首先执行Geofire查询以获取 key ,然后执行Firebase查询并创建与 key 相匹配的 User 对象将 User 附加到数组,然后通过 handler 返回.

然后在 CollectionView 中使用 User array ,问题在于,当 CollectionView 会显示,它仅显示一个 User 对象.

我在整个代码中放置了一些 print()行进行调试,发现每次附加项时该函数都通过 handler 传递数据,因此按时间的数组计数达到 VC ,这将显示 CollectionView 1 .

将以下行移动到 for循环括号之外会传递一个空的 array

如何更新我的函数,以便仅调用一次 handler 并传递完整的 array ?

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

这是函数:

 //获取当前位于半径50米的Venue位置的所有用户func getUsersAtVenue(forVenueLocation会场位置:CLLocation,forUid uid:字符串,处理程序:@转义(_用户:[User],_成功:Bool)->()){print("uid:\(uid)")var users = [User]()保护let currentLocation = LocationSingleton.sharedInstance.lastLocation else {return}//获取当前用户(设备)的位置let distanceApart = round(10 *(venueLocation.distance(from:currentLocation)/1000))/10//获取currentLocation和会场位置之间的距离并将Mts转换为Kms并四舍五入到小数点后两位如果distanceApart< = 50 {//如果距离在50公里之内,则继续let query = self.GEOFIRE_USERS_LOC.query(at:currentLocation,withRadius:50)//半径,单位为Kmsquery.observe(.keyEntered){(键:字符串!,userLocation:CLLocation!)在打印(键)self.REF_USERS.observeSingleEvent(of:.value,with:{(snapshot)in卫队让usersSnapshot = snapshot.children.allObjects作为?[DataSnapshot]否则{返回}适用于usersSnapshot {让discoverable = user.childSnapshot(forPath:"discoverable").value为!布尔如果user.key ==键&&发现==真{让uid = user.key让name = user.childSnapshot(forPath:"name").value as!细绳让email = user.childSnapshot(forPath:"email").value为!细绳让profilePictureURL = user.childSnapshot(forPath:"profilePictureURL").value为!细绳让Birthday = user.childSnapshot(forPath:"birthday").value as!细绳让firstName = user.childSnapshot(forPath:"firstName").value为!细绳让lastName = user.childSnapshot(forPath:"lastName").value为!细绳让性别= user.childSnapshot(forPath:"gender").value为!细绳让discoverable = user.childSnapshot(forPath:"discoverable").value为!布尔让online = user.childSnapshot(forPath:"online").value as!布尔让字典:[String:Any] = ["uid":uid,"name":名称,"email":电子邮件,"profilePictureURL":profilePictureURL,"birthday":生日,"firstName":firstName,"lastName":lastName,性别":性别,可发现":可发现,在线":在线]让用户=用户(uid:uid,词典:词典)users.append(用户)}//万一}//结尾于//从数组中过滤出当前用户让FilterUsers = users.filter({(user:User)-> Bool in return!user.uid.contains(uid)})print("filteredUsers count:\(filteredUsers.count)")//处理程序传递数组的改组版本handler(self.shuffleArray(array:filteredUsers)as![User],true)})//结束FIR快照调用}//结束地理查询}否则{//如果相距距离不在50公里之内,请执行此操作打印(您相距太远.")处理程序(用户,false)}}//结束功能 

控制台:

  uid:dBQd541pxlRypR7l1WT2utKVxdX2一些("dBQd541pxlRypR7l1WT2utKVxdX5")一些("dBQd541pxlRypR7l1WT2utKVxdX3")一些("dBQd541pxlRypR7l1WT2utKVxdX2")一些("dBQd541pxlRypR7l1WT2utKVxdX4")已过滤用户数:1用户数:1已过滤用户数:2用户数:2已过滤用户数:2用户数:2已过滤用户数:3用户数:3 

解决方案

对于地理查询范围内或范围内的每个关键字,都会触发 .keyEntered 事件.因此,一开始这意味着它会为范围内的所有键触发,并且从那一刻起,只要有新键进入范围(即,如果您在范围内添加新用户,或者用户移至范围内),它就会触发.>

听起来好像您想检测何时为所有初始用户调用了 .keyEntered .为此,您可以观察ready事件.

  query.observeReadyWithBlock({//处理程序传递数组的改组版本handler(self.shuffleArray(array:filteredUsers)as![User],true)}) 

如果您不希望在初始查询后获得有关新用户/移动用户的更新,这也是通过调用 removeObserverWithFirebaseHandle removeAllObservers .

另请参见等待查询就绪"'在Geofire文档中.

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

解决方案

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.

这篇关于Geofire/Firebase函数正在迅速执行处理程序多次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆