【问题标题】:Geofire/Firebase function is executing handler multiple times in swiftGeofire/Firebase 函数在 swift 中多次执行处理程序
【发布时间】:2018-06-06 14:19:25
【问题描述】:

我有以下函数,它使用 Geofire 获取用户列表,然后在嵌套设置中使用 Firebase 查询。

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

然后将User array 用于CollectionView,问题是当CollectionView 显示时它只显示一个User 对象。

我在代码中放置了一些 print() 行以进行调试,并发现该函数在每次附加项目时都通过 handler 传递数据,因此数组的计数达到 @显示CollectionView的987654333@是1

将以下行移到for loop 括号外传递一个空的array

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

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

函数如下:

    //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

控制台:

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

【问题讨论】:

    标签: swift firebase geofire


    【解决方案1】:

    .keyEntered 事件会针对您的地理查询范围内的每个键触发。所以最初这意味着它会为范围内的所有键触发,从那一刻起,只要有新键进入范围(即,如果您在范围内添加新用户,或者如果用户移动到范围内),它就会触发。

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

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

    如果您对在初始查询后获取新用户/移动用户的更新不感兴趣,这也是通过调用 removeObserverWithFirebaseHandleremoveAllObservers 删除您的观察者的好时机。

    另请参阅 Geofire 文档中的 waiting for queries to be 'ready'

    【讨论】:

    • 我实际上确实想在新用户出现和超出查询范围时获取更新,并相应地更新视图。我有一种感觉,我没有为此正确地构建我的代码。我正在调用上面的函数,然后将数组传递给显示 CollectionView 的 VC,然后只看到数组中的 1 个对象。如何构建显示 CollectionView 的 VC 以直接调用上面的函数,然后在数据更改时重新加载?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-29
    • 2011-12-12
    • 1970-01-01
    • 2014-01-15
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    相关资源
    最近更新 更多