Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CLGeocoder returns wrong results when city name is equal to some country's name (and not only)

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.

like image 580
Andriy Gordiychuk Avatar asked Jul 10 '15 01:07

Andriy Gordiychuk


1 Answers

Usage what you showed is completely right and I don't think there is anything else you can do to improve results. It is still just some complicated algorithm that tries to sort results based on set of rules and some assumption.

That being sad, I understand your frustration completely because I've been there and done that. The problem is that Geocoding database is not obviously complete and Apple is not the company who leads this field - Google is. Here you can see technical note from when the Geocoder was introduced saying that there are still countries that are not supported, or just partially supported.

So my suggestion to you is that if you want to get best results (though still not fail-proof), switch to Google Geolocation. For quite great amount of requests it is free and after that it costs some very minor amounts. The success rate is around 99% for all the basic searches from what I experienced and it only gets better if you provide more information. The API options are also quite extensive.

Here are links for developer documentation for both Geocoding and Reverse Geocoding: https://developers.google.com/maps/documentation/geocoding/intro https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse

Hope it helped at least a little.

EDIT: After I wrote this I did a little research and it seems that I am not the only person to make this claim (also including the same unsupported link).

like image 54
Jiri Trecak Avatar answered Oct 01 '22 09:10

Jiri Trecak