Pages

Wednesday 25 July 2012

Get country name from coordinates or coordinates from search term using Objective-C and Google API

One project I have been working on recently saw me messing around with Objective-C as I created an app using the MKMapView for interacting with Google Maps. I'm only hoping that when I release the app Apple aren't gonna be stupid and reject my app saying I might as well rewrite it using their new APIs as they're doing away with Google maps in iOS6. Oh well, we'll see...

Anyway, this time around I am posting a couple of methods that outline how I retrieve a country name by doing a JSON query passing in the latitude and longitude of a place, and secondly how I get the coordinates to a search term (a string).

As usual I'll let the code speak for itself...

To get the string name of a country from latitude and longitude, also with the ability to specify which language you get the country name back in...
// Do reverse geocode lookup on latitude/longitude to get country name based on specified locale
- (NSString*)getCountryNameFromCoordinates:(CLLocationCoordinate2D)coordinates locale:(NSString*)language;
{
    NSLog(@"Querying Google location API for %@ country name for latitude %f and longitude %f...", language, coordinates.latitude, coordinates.longitude);
    
    // Get JSON contents from Google API
    NSString *url = [[NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=false&language=%@", coordinates.latitude, coordinates.longitude, language] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"Query URL is: %@", url);
    NSError *error = nil;
    NSString *jsonString = [NSString stringWithContentsOfURL:[NSURL URLWithString:url] encoding:NSUTF8StringEncoding error:&error];
    if (error != nil)
    {
        NSLog(@"Error doing reverse geocode lookup on %f, %f, lang=%@: %@", coordinates.latitude, coordinates.longitude, language, error.localizedDescription);
        return nil;
    }

    // Extract country by parsing JSON data
    SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
    error = nil;
    NSDictionary *jsonObjects = [jsonParser objectWithString:jsonString error:&error];
    if (error != nil)
    {
        NSLog(@"Error parsing JSON response to reverse geocode lookup: %@", jsonParser.error);
        
        [jsonParser release];
        [jsonObjects release];

        return nil;
    }
    NSDictionary *results = [jsonObjects objectForKey:@"results"];
    NSString *country = nil;
    for (NSDictionary *item in results)
    {
        if ([[item objectForKey:@"types"] containsObject:@"country"])
        {
            country = [[[item objectForKey:@"address_components"] objectAtIndex:0] objectForKey:@"long_name"];
            NSLog(@"Found matching country name: %@", country);
            [item release];
            break;
        }
        
        [item release];
    }
    if (country == nil) {
        NSLog(@"Couldn't find a matching country name");
        
        [jsonParser release];
        [jsonObjects release];
        [results release];
        [country release];
        
        return nil;
    }
    
    [jsonParser release];
    [jsonObjects release];
    [results release];
    
    return country;
}

And to center your map (or whatever behaviour you so desire) on the coordinates obtained from a search on a specified location string...


- (void)searchCoordinatesForAddress:(NSString *)inAddress
{
    NSLog(@"Querying Google location API for latitude/longitude coordinates for search term %@", inAddress);
    
    // Get JSON contents from Google API
    NSString *url = [[NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?address=%@&sensor=false", inAddress] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"Query URL is: %@", url);
    NSError *error = nil;
    NSString *jsonString = [NSString stringWithContentsOfURL:[NSURL URLWithString:url] encoding:NSUTF8StringEncoding error:&error];
    if (error != nil)
    {
        NSLog(@"Error doing coordinate lookup on %@: %@", inAddress, error.localizedDescription);
        return;
    }
    
    // Extract coordinates by parsing JSON data
    SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
    error = nil;
    NSDictionary *jsonObjects = [jsonParser objectWithString:jsonString error:&error];
    if (error != nil)
    {
        NSLog(@"Error parsing JSON response to extract coordinates: %@", jsonParser.error);

        [jsonParser release];
        [jsonObjects release];
        
        return;
    }
    NSArray *results;
    NSDictionary *location;
    @try {
        results = [jsonObjects objectForKey:@"results"];
        location = [[[results objectAtIndex:0] objectForKey:@"geometry"] objectForKey:@"location"];
    }
    @catch (NSException *exception) {
        NSLog(@"Could not find searched location's coordinates");
        [jsonParser release];
        [jsonObjects release];
        return;
    }

    // Get latitude and longitude as double values
    double longitude = 0.0;
    double latitude = 0.0;   
    NSNumber *lat = [location objectForKey:@"lat"];
    NSNumber *lng = [location objectForKey:@"lng"];
    latitude = [lat doubleValue];
    longitude = [lng doubleValue];
    [lat release];
    [lng release];
    
    [jsonParser release];
    [jsonObjects release];
    [results release];
    
    if (longitude == 0 && latitude == 0) {
        NSLog(@"Could not find searched location's coordinates");
        return;
    }
    NSLog(@"Coordinates found for searched location: %f %f", latitude, longitude);
    
    // I zoom my map to the area in question.
    [self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
}

News

This blog hasn't had any activity for the past few months. After my wife and I embarked on our round the world trip back in February, stopping off home in New Zealand for our second wedding, we found out she was pregnant :)

We are delighted to say we will be expecting our first baby boy in October. We didn't end up completing most of the trip we had planned and instead I've been working for the past few months out of the UK. I will be moving back to Japan later this year and hope to refocus my efforts on augmented reality work then. Not that I am expecting much free time with fatherdom looming, but I will try and post the odd helpful article when I can!