iOS <5
There is no geocoding API. You need to ask Google:
http://maps.googleapis.com/maps/api/geocode/json?address=YOURADDRESS&sensor=true and parse the result using JSONKit.
Something like this:
-(CLLocation*) geocodeAddress:(NSString*) address {
NSLog(@"Geocoding address: %@", address);
// don't make requests faster than 0.5 seconds
// Google may block/ban your requests if you abuse the service
double pause = 0.5;
NSDate *now = [NSDate date];
NSTimeInterval elapsed = [now timeIntervalSinceDate:self.lastPetition];
self.lastPetition = now;
if (elapsed>0.0 && elapsed<pause){
NSLog(@" Elapsed < pause = %f < %f, sleeping for %f seconds", elapsed, pause, pause-elapsed);
[NSThread sleepForTimeInterval:pause-elapsed];
}
// url encode
NSString *encodedAddress = (NSString *) CFURLCreateStringByAddingPercentEscapes(
NULL, (CFStringRef) address,
NULL, (CFStringRef) @"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );
NSString *url = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?address=%@&sensor=true", encodedAddress];
//NSLog(@" url is %@", url);
[encodedAddress release];
// try twice to geocode the address
NSDictionary *dic;
for (int i=0; i<2; i++) { // two tries
HttpDownload *http = [HttpDownload new];
NSString *page = [http pageAsStringFromUrl:url];
[http release];
dic = [JsonParser parseJson:page];
NSString *status = (NSString*)[dic objectForKey:@"status"];
BOOL success = [status isEqualToString:@"OK"];
if (success) break;
// Query failed
// See http://code.google.com/apis/maps/documentation/geocoding/#StatusCodes
if ([status isEqualToString:@"OVER_QUERY_LIMIT"]){
NSLog(@"try #%d", i);
[NSThread sleepForTimeInterval:1];
} else if ([status isEqualToString:@"ZERO_RESULTS"]){
NSLog(@" Address unknown: %@", address);
break;
} else {
// REQUEST_DENIED: no sensor parameter. Shouldn't happen.
// INVALID_REQUEST: no address parameter or empty address. Doesn't matter.
}
}
// if we fail after two tries, just leave
NSString *status = (NSString*)[dic objectForKey:@"status"];
BOOL success = [status isEqualToString:@"OK"];
if (!success) return nil;
// extract the data
{
int results = [[dic objectForKey:@"results"] count];
if (results>1){
NSLog(@" There are %d possible results for this adress.", results);
}
}
NSDictionary *locationDic = [[[[dic objectForKey:@"results"] objectAtIndex:0] objectForKey:@"geometry"] objectForKey:@"location"];
NSNumber *latitude = [locationDic objectForKey:@"lat"];
NSNumber *longitude = [locationDic objectForKey:@"lng"];
NSLog(@" Google returned coordinate = { %f, %f }", [latitude floatValue], [longitude floatValue]);
// return as location
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]];
return [location autorelease];
}
+(NSDictionary*) parseJson:(NSString*) jsonString {
NSDictionary *rootDict = nil;
NSError *error = nil;
@try {
JKParseOptionFlags options = JKParseOptionComments | JKParseOptionUnicodeNewlines;
rootDict = [jsonString objectFromJSONStringWithParseOptions:options error:&error];
if (error) {
warn(@"%@",[error localizedDescription]);
}
NSLog(@" JSONKit: %d characters resulted in %d root node", [jsonString length], [rootDict count]);
} @catch (NSException * e) {
// If data is 0 bytes, here we get: "NSInvalidArgumentException The string argument is NULL"
NSLog(@"%@ %@", [e name], [e reason]);
// abort
rootDict = nil;
}
return rootDict;
}
iOS >= 5
iOS 5 has a geocoder API:
CLGeocoder* gc = [[CLGeocoder alloc] init];
[gc geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error)
{
if ([placemarks count]>0)
{
// get the first one
CLPlacemark* mark = (CLPlacemark*)[placemarks objectAtIndex:0];
double lat = mark.location.coordinate.latitude;
double lng = mark.location.coordinate.longitude;
}
}];
The CLPlacemark object has the following properties:
- name
- addressDictionary: Address Book keys and values for the placemark.
- ISOcountryCode
- country
- postalCode
- administrativeArea
- subAdministrativeArea
- locality
- subLocality
- thoroughfare: Street address.
- subThoroughfare: Address Book keys and values for the placemark.
- region
- inlandWater
- ocean
- areasOfInterest