Swift Firebase - 如何从 GeoFire 获取单个用户的位置
Swift Firebase -How to get individual user's location from GeoFire
1- 我应用中的所有用户每 2.5 分钟使用 Timer
.
将他们的位置发送到 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 ref 都有一个 "g"
child 和一个 "l"
child:
@geoLocations
|
@--abc123xyz456 // userId
|
@--g: "dr72xyz25abc" // geoFire id for this user's location in geoFire
|
@--l
|--0: 40.870431300779900 // latitude
|--1: -73.090007211987188 // longitude
这是实际数据库布局的图片
我不知道 "g"
代表什么,但我假设 "l"
代表位置,因为它的类型 CLLocation
正如 .observe(.keyEntered, with: { (key: String!, location: CLLocation!)
的参数中所述。
在数据库中,0
键和 1
被保存为 CLLocationDegrees
或 Double
数组的 snapshot.value
。
为了获得 latitude
和 longitude
,我使用了 let arr = snapshot.value as? [CLLocationDegrees]
,但 let arr = snapshot.value as? [Double]
也有效。
创建一个具有 child 名称的 ref,无论您的 geoLocations ref 的名称是什么 > 然后添加一个 child 的 userId > 然后添加一个 child 的 "l" 用于位置 child。
运行 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
}
}
1- 我应用中的所有用户每 2.5 分钟使用 Timer
.
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 ref 都有一个 "g"
child 和一个 "l"
child:
@geoLocations
|
@--abc123xyz456 // userId
|
@--g: "dr72xyz25abc" // geoFire id for this user's location in geoFire
|
@--l
|--0: 40.870431300779900 // latitude
|--1: -73.090007211987188 // longitude
这是实际数据库布局的图片
我不知道 "g"
代表什么,但我假设 "l"
代表位置,因为它的类型 CLLocation
正如 .observe(.keyEntered, with: { (key: String!, location: CLLocation!)
的参数中所述。
在数据库中,0
键和 1
被保存为 CLLocationDegrees
或 Double
数组的 snapshot.value
。
为了获得 latitude
和 longitude
,我使用了 let arr = snapshot.value as? [CLLocationDegrees]
,但 let arr = snapshot.value as? [Double]
也有效。
创建一个具有 child 名称的 ref,无论您的 geoLocations ref 的名称是什么 > 然后添加一个 child 的 userId > 然后添加一个 child 的 "l" 用于位置 child。
运行 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
}
}