In one of my apps I need to add an ability to find a city by its name. I am using CLGeocoder
to achieve this and I want it to have a behaviour identical to iOS weather app.
Below is the code which I have:
CLGeocoder().geocodeAddressString(searchBar.text!, completionHandler:{ (placemarks, error) -> Void in
guard let nonNilMarks = placemarks else {return}
for placemark in nonNilMarks {
print("locality: \(placemark.locality)")
print("name: \(placemark.name)")
print("country: \(placemark.country)")
print("formatted address: \(placemark.addressDictionary)")
}
})
It works very well in most cases. However, I recently noticed some cases when it fails. Below is the output for some examples:
Searching for 'Milan' - WORKS
locality: Optional("Milan")
name: Optional("Milan")
country: Optional("Italy")
formatted address: Optional([SubAdministrativeArea: Milan, State: Lombardy, CountryCode: IT, Country: Italy, Name: Milan, FormattedAddressLines: (
Milan,
Italy
), City: Milan])
This is the correct output
Searching for 'Italy, TX' - WORKS
There is a town in Texas called Italy. If I type 'Italy, TX' the output is:
locality: Optional("Italy")
name: Optional("Italy")
country: Optional("United States")
formatted address: Optional([SubAdministrativeArea: Ellis, State: TX, CountryCode: US, Country: United States, Name: Italy, FormattedAddressLines: (
"Italy, TX",
"United States"
), City: Italy])
Searching for 'Italy' - FAILS
When I type just 'Italy' I only get place mark for the country:
locality: nil
name: Optional("Italy")
country: Optional("Italy")
formatted address: Optional([CountryCode: IT, Name: Italy, FormattedAddressLines: (
Italy
), Country: Italy])
Searching for 'Singapore, Singapore' - WORKS
This is similar to the case with 'Italy, TX':
locality: Optional("Singapore")
name: Optional("Singapore")
country: Optional("Singapore")
formatted address: Optional([City: Singapore, CountryCode: SG, Name: Singapore, State: Singapore, FormattedAddressLines: (
Singapore,
Singapore
), Country: Singapore])
Searching for 'Singapore' - FAILS
Again, seems similar to the case with 'Italy'. It only finds a country:
locality: nil
name: Optional("Singapore")
country: Optional("Singapore")
formatted address: Optional([CountryCode: SG, Name: Singapore, FormattedAddressLines: (
Singapore
), Country: Singapore])
Preliminary guess
At this stage I though that maybe geocodeAddressString:
stops searching if it finds a country with the name equal to the search parameter, so I tried changing my code to :
let addrDict = [kABPersonAddressCityKey as NSString: searchBar.text!]
CLGeocoder().geocodeAddressDictionary(addrDict, completionHandler:{ (placemarks, error) -> Void in
print(placemarks)
})
I thought that by restricting the search term to the city name I would get correct results. Unfortunately, I get the exact same behaviour!
And THEN I realised that I have problems not only with cases when city name is equal to the country name.
Searching for 'Tokyo' - EPIC FAIL
locality: nil
name: Optional("Tokyo")
country: Optional("Japan")
formatted address: Optional([CountryCode: JP, Name: Tokyo, State: Tokyo, FormattedAddressLines: (
Tokyo,
Japan
), Country: Japan])
Conclusion
Not only can CLGeocoder
omit results (like in the case of 'Italy') but it can also tell me that a place does not have a locality
when, in fact, it does (I believe last time I checked a map Tokyo was still a city!).
Does anyone know how I can resolve any of these issues?
Weather app does it somehow - searching for 'Singapore' or 'Italy' there gives correct results. I will be grateful for any help!
P.S. Although I am using Swift I am adding Objective-C as a tag as I think that this question is not Swift specific.