I'd like to perform a location lookup like the Apple Weather app which shows a table of potential locations with each keystroke. I'm sending the user's input string to the function below each time an "editing changed" event occurs in the text field. The string seems to be sent properly, but I'm not getting back the expected array of placemarks. For example "Chestnut" returns only "Chestnut, IL", but if I type "Chestnut Hi" I get four elements: "Marshfield, MA", "Wilbraham, MA", "South Hadley, MA", and "Greenfield, MA". Then typing "Chesnut Hil" returns "Brookline, MA", which wasn't even in the "Chestnut Hi" list. Code is below. Thanks much!
func forwardGeocoding(address: String) {
CLGeocoder().geocodeAddressString(address, completionHandler: { (placemarks, error) in
if error != nil {
print(error!)
return
}
var placeName = ""
var placeCoordinate = ""
self.placeNames = [] // empty arrays at the start of each geocode result
self.placeCoordinates = []
if (placemarks?.count)! > 0 {
for placemark in placemarks! {
if placemark.country != "United States" {
let city = placemark.locality ?? ""
let country = placemark.country ?? ""
placeName = "\(city) \(country)"
} else {
let city = placemark.locality ?? ""
placeName = "\(city), \(placemark.administrativeArea!)"
}
let coordinate = placemark.location?.coordinate
placeCoordinate = "\(coordinate!.latitude), \(coordinate!.longitude)"
self.placeNames.append(placeName)
self.placeCoordinates.append(placeCoordinate)
}
}
self.tableView.reloadData()
})
}
Some notable snippets from the
CLGeocoderdocs, emphasis added:All of this suggests that a) using
CLGeocoderto return and refine "as you type" search results is probably not going to work well, in general, and b) therefore it's probably not what Apple's using in Weather.Remember that Weather doesn't want to map user-entered strings to lat/longs on the globe — it's searching against a list of place names. (Specifically, the list of places for which Apple's weather forecast partners provide data.) If that's the kind of thing you want to search against, you'll need your own such list.
If you want "as you type" search results, you're best served by a local database, or at the very least a web service that's tailored to that use. As noted in this old answer, there are plenty of options for that — Google offers some services, and GeoNames.org is a free/open option that has both web services and downloadable databases that you could embed in your app.
Once you have such a database/service, you'll also want to think about how you use it. For example, Do you want "chestnut hi" to find Chestnut Hill, PA or (hypothetically; there isn't one) Chestnut, Hawaii? How you preprocess search strings and make them into database queries will affect your results.