ios - Swift Firebase -如何从 GeoFire 获取单个用户的位置

标签 ios swift firebase geolocation

1- 我的应用中的所有用户使用 Timer 每 2.5 分钟将其位置发送到 GeoFire

2- 其他用户也会查询 GeoFire 以查找距离他们 1 英里半径内的用户(例如 10 个用户)。我获取这 10 个用户,然后将它们添加到一个数组中。

3- 然后,我使用这 10 个用户的 userId(geoRef 键)循环遍历数组。我去他们的数据库引用并搜索,看看它们是否符合某些标准。如果他们这样做,我将它们添加到不同的数组(例如,现在有 5 个用户在此子集数组中)

4- 由于每 2.5 分钟每个用户的位置都会发送到 GeoFire,这意味着该子集中的 5 个用户可能具有与首次添加到子集数组时不同的位置。

我可以使用计时器来查询这 5 个用户的位置。问题是如何查询 GeoFire 以仅从这 5 个用户中获取每个用户的位置?我不想再次查询该 1 英里区域内的每个人,否则它会得到相同的信息10 位用户

// I have a Timer firing this off
func queryLocationOfSubsetOfUsersInRadius() {

    let geofireRef = Database.database().reference().child("geoLocations")
    let geoFire = GeoFire(firebaseRef: geoFireRef)

    let dispatchGroup = DispatchGroup()

    for user in subsetOfUsersInRadius {

        dispatchGroup.enter()

        let userId = user.userId

        // I don't know if this is the right method to use. I only added it here because I saw it has observeValue on it
        geoFire.observeValue(forKeyPath: userId, of: Any?, change: NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)

            // *** HOW TO GET THE USERS NEW LOCATION and use dispatchGroup.leave() as each one is obtained??? ***

            dispatchGroup.leave()
    }

    dispatchGroup.notify(queue: .global(qos: .background)) {

       // now animate the annotation from the user's inital old location (if they moved) on the mapView to their new location on the mapView. It's supposed to look like Uber's cars moving. Happens on main thread
    }
}

下面的支持代码

var queryHandle: UInt?
var regionQuery: GFRegionQuery?

var usersInRadius = [User]() // has 10 users
var subsetOfUsersInRadius = [User]() // of the 10 only 5 fit some criteria

let geofireRef = Database.database().reference().child("geoLocations")
let geoFire = GeoFire(firebaseRef: geofireRef)

// region: MKCoordinateRegion was previously set at 1 mile 1609.344 meters

regionQuery = geoFire.query(with: region)
queryHandle = regionQuery?.observe(.keyEntered, with: { [weak self](key: String!, location: CLLocation!) in

    let user = User()
    user.userId = key
    user.location = location

    self?.usersInRadius.append(user)
})

regionQuery?.observeReady({ [weak self] in

    self?.sortUsersInRadius(arr: self!.usersInRadius)
})

func sortUsersInRadius(arr: [User]) {

    if let queryHandle = queryHandle {
        regionQuery?.removeObserver(withFirebaseHandle: queryHandle)
    }

    let dispatchGroup = DispatchGroup()

    for user in arr {

        let userId = user.userId

        someDatabaseRef.child(userId).observeSingleEvent(of: .value, with: { (snapshot) in

             // if snapshot contains some critera add that user to the subSet array

             self?.subsetOfUsersInRadius.append(user) // only 5 users fit this criteria

             dispatchGroup.leave()
        })
    }

    dispatchGroup.notify(queue: .global(qos: .background)) {

       // add an annotation to mapView to show the initial location of each user from subsetOfUsersInRadius. Happens on main thread
    }
}

最佳答案

在数据库内,每个 userId 位置的 GeoFire 引用都有一个 "g" 子级和 "l" 子级:

@geoLocations
      |
      @--abc123xyz456 // userId
           |
           @--g: "dr72xyz25abc" // geoFire id for this user's location in geoFire
           |
           @--l
              |--0: 40.870431300779900 // latitude
              |--1: -73.090007211987188 // longitude

这是实际数据库布局的图片

enter image description here

我不知道 "g" 代表什么,但我假设 "l" 代表位置,因为它的类型是 CLLocation.observe(.keyEntered, with: { (key: String!, location: CLLocation!) 的参数中声明。

在数据库内部,0 键和 1 被保存为 CLLocationDegrees 数组的 snapshot.value

为了获取纬度经度,我使用了let arr = snapshot.value as? [CLLocationDegrees] 但是 让 arr = snapshot.value 为? [Double] 也有效。

创建一个引用,其子名称与您的地理位置引用的名称相同>然后添加 userId 的子名称>然后为位置子名称添加“l”的子名称。

运行 observeSingleEvent(of: .value ) 并在回调中将 snapshot.value 转换为 [CLLocationDegrees] 数组

// *** if using CLLocationDegrees be to import CoreLocation ***
import CoreLocation

let geoLocationsRef = Database.database().reference()
                        .child("geoLocations") // name of my geoRef in Firebase
                        .child("abc123xyz456") // the userId I'm observing
                        .child("l") // the "l" is the child to observe

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

    if !snapshot.exists() { return }

    guard let arr = snapshot.value as? [CLLocationDegrees] else { return }

    if arr.count > 1 {

        let latitude = arr[0]
        print(latitude)

        let longitude = arr[1]
        print(longitude)

        // do whatever with the latitude and longitude
    }
})

这是我使用dispatchGroup()的问题的答案:

func queryLocationOfSubsetOfUsersInRadius() {

    let dispatchGroup = DispatchGroup()

    for user in subsetOfUsersInRadius {

        dispatchGroup.enter()

        let userId = user.userId

        let geoLocationsRef = Database.database().reference()
            .child("geoLocations")
            .child(userId)
            .child("l")

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

            // this user may have deleted their location
            if !snapshot.exists() {
                dispatchGroup.leave()
                return
            }

            guard let arr = snapshot.value as? [CLLocationDegrees] else {
                dispatchGroup.leave()
                return
            }

            if arr.count > 1 {

                let latitude = arr[0]
                print(latitude)

                let longitude = arr[1]
                print(longitude)

                // do whatever with the latitude and longitude
            }

            dispatchGroup.leave()
        })
    }

    dispatchGroup.notify(queue: .global(qos: .background)) {

        // now animate the annotation from the user's inital old location (if they moved) on the mapView to their new location on the mapView. It's supposed to look like Uber's cars moving. Happens on main thread
    }
}

关于ios - Swift Firebase -如何从 GeoFire 获取单个用户的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56195680/

相关文章:

firebase - MissingPluginException(在 channel firebase_messaging 上找不到 Messaging#requestPermission 方法的实现

java - 安卓火力地堡 : Second Connected Database not allowing auth in rules

ios - 不使用 Swift 显示小数

ios - Swift - 当您的应用程序处于后台模式时,如何向屏幕添加横幅?

ios - 使用 Swift 在 iOS 中远程控制事件

arrays - Swift Array reversed() 函数 O(1) 复杂度?

firebase - 如何访问自定义声明?

ios - 视频可以从浏览器播放,但不能在电影播放器​​上播放 -SWIFT

ios - iPhone私有(private)API编译

swift - 创建带参数的类的实例