按用户位置距 firebase 的距离对数组进行排序

Дми*_*аев 2 userlocation ios firebase swift firebase-realtime-database

无法弄清楚如何对用户附近的地址进行自动排序。我不明白从哪里开始以及如何编写代码。

\n\n

我的firebase中有地址。地址的类型为字符串(不是纬度/经度)。例子:

\n\n
"\xd0\x9c\xd0\xbe\xd1\x81\xd0\xba\xd0\xb2\xd0\xb0, \xd0\xad\xd0\xbb\xd0\xb5\xd0\xba\xd1\x82\xd1\x80\xd0\xbe\xd0\xb7\xd0\xb0\xd0\xb2\xd0\xbe\xd0\xb4\xd1\x81\xd0\xba\xd0\xb0\xd1\x8f, 21"\n"\xd0\x9c\xd0\xbe\xd1\x81\xd0\xba\xd0\xb2\xd0\xb0, \xd0\x90\xd1\x80\xd0\xb1\xd0\xb0\xd1\x82, \xd0\xa1\xd1\x82\xd0\xb0\xd1\x80\xd0\xbe\xd0\xba\xd0\xbe\xd0\xbd\xd1\x8e\xd1\x88\xd0\xb5\xd0\xbd\xd0\xbd\xd1\x8b\xd0\xb9 \xd0\xbf\xd0\xb5\xd1\x80\xd0\xb5\xd1\x83\xd0\xbb\xd0\xbe\xd0\xba, \xd0\xb4\xd0\xbe\xd0\xbc 43"\n"\xd0\x9c\xd0\xbe\xd1\x81\xd0\xba\xd0\xb2\xd0\xb0, \xd1\x83\xd0\xbb\xd0\xb8\xd1\x86\xd0\xb0 1-\xd1\x8f \xd0\x91\xd1\x83\xd1\x85\xd0\xb2\xd0\xbe\xd1\x81\xd1\x82\xd0\xbe\xd0\xb2\xd0\xb0, \xd0\xb4\xd0\xbe\xd0\xbc 12/11, \xd0\xba\xd0\xbe\xd1\x80\xd0\xbf\xd1\x83\xd1\x81 53"\n
Run Code Online (Sandbox Code Playgroud)\n\n

我知道什么需要使用firebase 的查询,但是如何使用查询,我现在不明白。

\n\n

这是我的代码:

\n\n
class PhotoStudiosViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate {\n\n    @IBOutlet weak var tableView: UITableView!\n\n    var theStudios: [Studio] = []\n\n    var studiosRef: DatabaseReference!\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(true)\n\n        tableView.estimatedRowHeight = 475\n        tableView.rowHeight = UITableViewAutomaticDimension\n\n        loadDataFromFirebase()\n\n    }\n\n    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {\n\n        return theStudios.count\n    }\n\n    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {\n        let cell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath) as! PhotoStudiosTableViewCell\n\n        cell.addressLabel.text = theStudios[indexPath.row].studioAddress\n\n        return cell\n    }\n\n    func loadDataFromFirebase() {\n\n        studiosRef = Database.database().reference(withPath: "Addresses")\n\n        let time = DispatchTime.now() + 0.5 \n\n        studiosRef.observe(.value, with: { (snapshot) in\n\n        DispatchQueue.main.asyncAfter(deadline: time) {\n\n            for imageSnap in snapshot.children {\n\n                let studioObj = Studio(snapshot: imageSnap as! DataSnapshot)\n\n                self.theStudios.append(studioObj)\n\n            }\n\n            self.tableView.reloadData()\n\n        }\n\n    })\n\n}\n\n\n\nclass Studio {\n\n    var ref: DatabaseReference! \n    var studioAddress: String = ""\n\n    init(snapshot: DataSnapshot) {\n\n        ref = snapshot.ref\n        studioName = snapshot.key\n\n        let value = snapshot.value as! NSDictionary \n\n        studioAddress = value["address"] as? String ?? "---"\n\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如何使用firebase中的数据对用户附近的地址进行自动排序

\n

Fra*_*len 5

这是一个复杂的过程,需要多个步骤。我将尝试解释这些步骤,但您必须做相当多的工作才能将其变成有效的解决方案。

地理编码

首先:像您拥有的那样的地址字符串不是位置。计算机无法比较两个这样的字符串并可靠地知道它们之间的距离。

因此,您要做的第一件事就是将地址转换为更可靠的位置指示,即转换为纬度和经度(又名纬度/经度)。将地址转换为纬度/经度的过程称为地理编码。这并不是一门精确的科学,但有很多服务在地理编码方面非常擅长。

在此地理编码过程结束时,您将获得每个地址的纬度/经度组合。这又把问题带回了数学,这是一门更加精确的科学。

地理查询

接下来,您需要比较每个地址的纬度/经度并计算它们之间的距离。这一门相对精确的科学,如果你愿意忽略两极附近的误差和类似的事情的话。

不幸的是,Firebase 实时数据库本身只能对单个属性进行排序/过滤。由于位置由两个属性(纬度和经度)组成,因此如果没有一些魔法,它就无法过滤位置。

幸运的是,有人想出了一种将纬度/经度信息转换为单个字符串的方法,称为geohash。例如:旧金山的 Google 办公室位于 lat/lon 37.7900515,-122.3923805,翻译为 geohash 9q8yyz。山景城的 Googleplex 位于 lat/lon 37.4219999,-122.0862515,翻译为 geohash 9q9hvu

与您开始使用的地址不同,geohash 非常具有可比性。引用(链接的)维基百科解释:

附近的地方[有]相似的前缀。共享前缀越长,两个地方越接近。

在上面的两个示例中,您可以看到这两个位置彼此相对较近,因为它们都以9q

Firebase 有一个名为 GeoFire 的开源库,它:

  1. 可以轻松地将位置(您必须具有纬度/经度)存储在 Firebase 中作为 geohashes。
  2. 提供查询功能,以便您可以获得指定位置最大距离内的节点。

我建议您查看iOS 版本的 GeoFire