Can't figure out how to do automatic sorting addresses near the user. I can not understand where to start and how to write code.
I have addresses in my firebase. Addresses have type string (not latitude / longitude). Example:
"Москва, Электрозаводская, 21"
"Москва, Арбат, Староконюшенный переулок, дом 43"
"Москва, улица 1-я Бухвостова, дом 12/11, корпус 53"
I know what need use query from firebase, but how use query, i don't understand now.
It's my code:
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 ?? "---"
}
}
How to make an automatic sorting addresses near the user using data from firebase?
This is a complex process, requiring multiple steps. I'll try to explain the steps, but you'll have to do quite some work to turn it into a functioning solution.
First up: an address string like the one you have is not a location. There is no way for a computer to compare two of such strings and reliably know how far apart they are.
So the first thing you'll have to do is to turn the addresses into a more reliable indication of a location, i.e. into a latitude and longitude (a.k.a. lat/lon). The process of turning an address into lat/lon is known as geocoding. It is not really an exact science, but there are plenty of services that are quite good at this geocoding bit.
At the end of this geocoding process you will have a lat/lon combination for each address. That puts the problem back into mathematics, which is a much more exact science.
Next up you'll need to compare the lat/lon of each address and calculate the distance between them. This is a relatively exact science, if you're willing to ignore inaccuracies near the poles and things like that.
Unfortunately the Firebase Realtime Database can natively only order/filter on a single property. Since a location consists of two properties (latitude and longitude) it can't filter on location without some magic.
Luckily somebody came up with a way to translate lat/lon information into a single string, known as a geohash. For example: the Google office in San Francisco is at lat/lon 37.7900515,-122.3923805
, which translate to geohash 9q8yyz
. The Googleplex in Mountain View is at lat/lon 37.4219999,-122.0862515
, which translates to geohash 9q9hvu
.
Unlike the addresses you started with, geohashes are very nicely comparable. To quote the (linked) wikipedia explanation:
nearby places [have] similar prefixes. The longer a shared prefix is, the closer the two places are.
In our two examples above, you can see the the two locations are relatively close to each other because they both start with 9q
There is an open-source library for Firebase called GeoFire that:
I recommend that you check out the iOS version of GeoFire.