按用户位置与 firebase 之间的距离对数组进行排序
Sort array by distance near user location from firebase
不知道如何在用户附近自动分类地址。我不明白从哪里开始以及如何编写代码。
我的 firebase 中有地址。地址的类型为字符串(不是纬度/经度)。示例:
"Москва, Электрозаводская, 21"
"Москва, Арбат, Староконюшенный переулок, дом 43"
"Москва, улица 1-я Бухвостова, дом 12/11, корпус 53"
我知道什么需要使用firebase的query,但是如何使用query,我现在不明白。
这是我的代码:
class PhotoStudiosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate {
@IBOutlet weak var tableView: UITableView!
var theStudios: [Studio] = []
var studiosRef: DatabaseReference!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
tableView.estimatedRowHeight = 475
tableView.rowHeight = UITableViewAutomaticDimension
loadDataFromFirebase()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theStudios.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! PhotoStudiosTableViewCell
cell.addressLabel.text = theStudios[indexPath.row].studioAddress
return cell
}
func loadDataFromFirebase() {
studiosRef = Database.database().reference(withPath: "Addresses")
let time = DispatchTime.now() + 0.5
studiosRef.observe(.value, with: { (snapshot) in
DispatchQueue.main.asyncAfter(deadline: time) {
for imageSnap in snapshot.children {
let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)
self.theStudios.append(studioObj)
}
self.tableView.reloadData()
}
})
}
class Studio {
var ref: DatabaseReference!
var studioAddress: String = ""
init(snapshot: DataSnapshot) {
ref = snapshot.ref
studioName = snapshot.key
let value = snapshot.value as! NSDictionary
studioAddress = value["address"] as? String ?? "---"
}
}
如何使用来自 firebase 的数据在用户附近自动排序 地址?
这是一个复杂的过程,需要多个步骤。我将尝试解释这些步骤,但您必须做很多工作才能将它变成一个有效的解决方案。
地理编码
首先:像您这样的地址字符串不是位置。计算机无法比较两个这样的字符串并可靠地知道它们相距多远。
因此,您要做的第一件事就是将地址转换为更可靠的位置指示,即转换为纬度和经度 (a.k.a。lat/lon)。将地址转换为 lat/lon 的过程称为 geocoding。这并不是一门真正精确的科学,但有很多服务非常擅长这个地理编码位。
在此地理编码过程结束时,每个地址都会有一个 lat/lon 组合。这就把问题带回了数学,这是一门更精确的科学。
地理查询
接下来您需要比较每个地址的 lat/lon 和 calculate the distance between them。这是一门相对精确的科学,如果你愿意忽略两极附近的不准确性和类似的东西。
不幸的是,Firebase 实时数据库本身只能 order/filter 在单个 属性 上。由于一个位置由两个属性(纬度和经度)组成,所以如果没有一些魔法,它就无法过滤位置。
幸运的是,有人提出了一种将 lat/lon 信息转换为单个字符串的方法,称为 geohash. For example: the Google office in San Francisco 位于 lat/lon 37.7900515,-122.3923805
,转换为 geohash 9q8yyz
。山景城的 Googleplex 位于 lat/lon 37.4219999,-122.0862515
,转换为 geohash 9q9hvu
.
与您开始使用的地址不同,geohashes 具有很好的可比性。引用(链接的)维基百科解释:
nearby places [have] similar prefixes. The longer a shared prefix is, the closer the two places are.
在我们上面的两个示例中,您可以看到这两个位置彼此相对较近,因为它们都以 9q
开头
有一个名为 GeoFire 的 Firebase 开源库:
- 可以很容易地在 Firebase 中将位置(您必须具有 lat/lon)存储为 geohashes。
- 提供查询功能,以便您可以获得指定位置的最大距离内的节点。
我建议您查看 iOS version of GeoFire。
不知道如何在用户附近自动分类地址。我不明白从哪里开始以及如何编写代码。
我的 firebase 中有地址。地址的类型为字符串(不是纬度/经度)。示例:
"Москва, Электрозаводская, 21"
"Москва, Арбат, Староконюшенный переулок, дом 43"
"Москва, улица 1-я Бухвостова, дом 12/11, корпус 53"
我知道什么需要使用firebase的query,但是如何使用query,我现在不明白。
这是我的代码:
class PhotoStudiosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate {
@IBOutlet weak var tableView: UITableView!
var theStudios: [Studio] = []
var studiosRef: DatabaseReference!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
tableView.estimatedRowHeight = 475
tableView.rowHeight = UITableViewAutomaticDimension
loadDataFromFirebase()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return theStudios.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! PhotoStudiosTableViewCell
cell.addressLabel.text = theStudios[indexPath.row].studioAddress
return cell
}
func loadDataFromFirebase() {
studiosRef = Database.database().reference(withPath: "Addresses")
let time = DispatchTime.now() + 0.5
studiosRef.observe(.value, with: { (snapshot) in
DispatchQueue.main.asyncAfter(deadline: time) {
for imageSnap in snapshot.children {
let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)
self.theStudios.append(studioObj)
}
self.tableView.reloadData()
}
})
}
class Studio {
var ref: DatabaseReference!
var studioAddress: String = ""
init(snapshot: DataSnapshot) {
ref = snapshot.ref
studioName = snapshot.key
let value = snapshot.value as! NSDictionary
studioAddress = value["address"] as? String ?? "---"
}
}
如何使用来自 firebase 的数据在用户附近自动排序 地址?
这是一个复杂的过程,需要多个步骤。我将尝试解释这些步骤,但您必须做很多工作才能将它变成一个有效的解决方案。
地理编码
首先:像您这样的地址字符串不是位置。计算机无法比较两个这样的字符串并可靠地知道它们相距多远。
因此,您要做的第一件事就是将地址转换为更可靠的位置指示,即转换为纬度和经度 (a.k.a。lat/lon)。将地址转换为 lat/lon 的过程称为 geocoding。这并不是一门真正精确的科学,但有很多服务非常擅长这个地理编码位。
在此地理编码过程结束时,每个地址都会有一个 lat/lon 组合。这就把问题带回了数学,这是一门更精确的科学。
地理查询
接下来您需要比较每个地址的 lat/lon 和 calculate the distance between them。这是一门相对精确的科学,如果你愿意忽略两极附近的不准确性和类似的东西。
不幸的是,Firebase 实时数据库本身只能 order/filter 在单个 属性 上。由于一个位置由两个属性(纬度和经度)组成,所以如果没有一些魔法,它就无法过滤位置。
幸运的是,有人提出了一种将 lat/lon 信息转换为单个字符串的方法,称为 geohash. For example: the Google office in San Francisco 位于 lat/lon 37.7900515,-122.3923805
,转换为 geohash 9q8yyz
。山景城的 Googleplex 位于 lat/lon 37.4219999,-122.0862515
,转换为 geohash 9q9hvu
.
与您开始使用的地址不同,geohashes 具有很好的可比性。引用(链接的)维基百科解释:
nearby places [have] similar prefixes. The longer a shared prefix is, the closer the two places are.
在我们上面的两个示例中,您可以看到这两个位置彼此相对较近,因为它们都以 9q
有一个名为 GeoFire 的 Firebase 开源库:
- 可以很容易地在 Firebase 中将位置(您必须具有 lat/lon)存储为 geohashes。
- 提供查询功能,以便您可以获得指定位置的最大距离内的节点。
我建议您查看 iOS version of GeoFire。