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

时间:2019-05-18 03:13:26

标签: ios swift firebase geolocation

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

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

3-然后,我使用这10个用户的userId(geoRef键)在数组中循环。我去他们的数据库参考,并搜索是否符合某些条件。如果可以,我将它们添加到另一个数组中(例如,此subSet数组中现在有5个用户)

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

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

GeoFire

下面的支持代码

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

1 个答案:

答案 0 :(得分:0)

在数据库内部,每个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被保存为snapshot.valueCLLocationDegrees的数组的Double

为了获得latitudelongitude,我使用了let arr = snapshot.value as? [CLLocationDegrees],但let arr = snapshot.value as? [Double]也起作用。

创建一个引用,该引用的子名称与geoLocations引用的名称相同,然后>添加userId的子代>然后为location子代添加“ 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
    }
}