Tags
Archive
2014
September
2012
January
Forward Geocoding
: 23 Jan 2012
by Andy Riordan
In iOS 5, Apple introduced a great new feature: forward geocoding. Forward here is as opposed to reverse geocoding, which has been present since MapKit was introduced. Where reverse geocoding takes a longitude/latitude pair and converts it to city, state, zip code and so on, forward geocoding takes a city, state, zip code kind of thing and turns it into a lat/long.
First try
Here’s a simple snippet to try forward geocoding on iOS 5. Make sure you have CoreLocation.framework in your Frameworks section, then include the header:
#import <CoreLocation/CoreLocation.h>
Then, to test it out:
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLGeocodeCompletionHandler completionHandler =
^(NSArray *placemarks, NSError *error)
{
if ([placemarks count] > 0)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(@"Found placemark: %@", placemark);
}
};
[geocoder geocodeAddressString:@"Outer Mongolia" completionHandler:completionHandler];
Note: For brevity, this snippet leaks geocoder
if not run on ARC. The sample code provided releases it correctly.
If you run it in the iOS 5 simulator (or device), it will work great. Turns out Outer Mongolia is really a place:
Forward Geocoding[1902:f803] Found placemark: Outer Mongolia, Mongolia @ <+47.00000000,+103.00000000> +/- 100.00m, region (identifier <+47.00019850,+103.00094600> radius 129.34) <+47.00019850,+103.00094600> radius 129.34m
Warnings
It’s great that we can specify location information with such free syntax. However, with that great power comes great responsibility. Let’s say you have a perfectly normal-sounding US zip code, 38720
. That zip code belongs to Duncan, MS. However, when we run it through Core Location, we get this:
Forward Geocoding[7123:f803] Found placemark: 38720 Kankaanpaa, Finland @ <+61.74309935,+22.56331008> +/- 100.00m, region (identifier <+61.74316400,+22.57415800> radius 9380.53) <+61.74316400,+22.57415800> radius 9380.53m
That’s in Finland, folks. Not quite what we were looking for. However, we do get an array of placemarks back - perhaps it’s somewhere in the array, just not the first object?
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLGeocodeCompletionHandler completionHandler =
^(NSArray *placemarks, NSError *error)
{
for (CLPlacemark *placemark in placemarks)
{
NSLog(@"Found placemark: %@", placemark);
}
};
[geocoder geocodeAddressString:@"38720" completionHandler:completionHandler];
Forward Geocoding[8216:f803] Found placemark: 38720 Kankaanpaa, Finland @ <+61.74309935,+22.56331008> +/- 100.00m, region (identifier <+61.74316400,+22.57415800> radius 9380.53) <+61.74316400,+22.57415800> radius 9380.53m
Forward Geocoding[8216:f803] Found placemark: Duncan, MS 38720, United States @ <+34.11106550,-90.82042082> +/- 100.00m, region (identifier <+34.10980250,-90.82122800> radius 15440.36) <+34.10980250,-90.82122800> radius 15440.36m
Forward Geocoding[8216:f803] Found placemark: 38720 San Andrés y Sauces (Canary Islands), Spain @ <+28.77990090,-17.79729925> +/- 100.00m, region (identifier <+28.78246300,-17.79785150> radius 6970.58) <+28.78246300,-17.79785150> radius 6970.58m
Okay, so it found it after all - it’s the second item in the array, not the first. We can just filter out the non-US results and we’ll be fine. However, why not let Core Location do that for us? Instead, let’s be more specific and use 38720 United States
:
Forward Geocoding[7214:f803] Found placemark: Duncan, MS 38720, United States @ <+34.11106550,-90.82042082> +/- 100.00m, region (identifier <+34.10980250,-90.82122800> radius 15440.36) <+34.10980250,-90.82122800> radius 15440.36m
Ahh, there we go. The moral here is to be careful and specify as much information as you have. I learned that one the hard way.
Legacy OS versions
Unfortunately, when you run this code on iOS 4, you get no output. As mentioned above, forward geocoding is an iOS 5 feature. If you need it on iOS versions earlier than 5, there are a few options, including:
- Third-party geocoding services
- In-storage geocoding database
Conclusion
Where might this be useful? Beyond the obvious uses, like allowing a user to input a zip code or city/state name and having it come back with locations when your server only supports lat/long searching, you can now display city details rather than just “Current Location”.
Go forth and geocode!