Swift Firebase - Как получить местоположение отдельного пользователя из GeoFire - PullRequest
0 голосов
/ 18 мая 2019

1- Все пользователи моего приложения отправляют свое местоположение на GeoFire каждые 2,5 минуты, используя Timer.

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

1 Ответ

0 голосов
/ 18 мая 2019

Внутри базы данных ссылка GeoFire каждого местоположения userId имеет "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.value массива либо CLLocationDegrees, либо Double.

Для получения latitude и longitude Я использовал let arr = snapshot.value as? [CLLocationDegrees], но let arr = snapshot.value as? [Double] также работал.

Создайте ссылку, у которой есть дочернее имя независимо от того, какое имя у вашей ссылки geoLocations есть>, затем добавьте дочерний элемент 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
    }
}
...