iphoneioscocoa-touchmkmapviewmkreversegeocoder

How to search MKMapView with UISearchBar?


I have an application that needs to have a similar search feature like the Apple "Maps" application (included with iPhone, iPod Touch and iPad).

The feature in question should not be a hard thing to do, but I'm really clueless about how to input a Street Address in the search bar, and then obtaining coordinates for that address or something that can help me to actually move the map and center in that place.

I mean, what do I have to query, does Apple provide an "address searching API method" ? or I need to use the google maps API directly ?

I would love to hear how should it be done.


Solution

  • Ok, to answer my own question:

    As was mentioned before, the best thing to do is to use the Google Maps API, it supports a lot of formats but for several reasons I chose to go with JSON.

    So here are the steps to perform a JSON query to Google Maps and obtain the coordinate of the query. Note that not all the correct validations are done, this is only a Proof of concept.

    1) Download a JSON framework/library for the iPhone, there are several, I chose to go with this one, it's very good and seems an active project, plus several comercial applications seem to be using it. So add it to your project ( instructions here ).

    2) To query Google Maps for an address we need to build a request URL like this: http://maps.google.com/maps/geo?q=Paris+France

    This url, will return a JSON object for the query "Paris+France".

    3) Code:

    //Method to handle the UISearchBar "Search", 
    - (void) searchBarSearchButtonClicked:(UISearchBar *)theSearchBar 
    {
        //Perform the JSON query.
        [self searchCoordinatesForAddress:[searchBar text]];
    
        //Hide the keyboard.
        [searchBar resignFirstResponder];
    }
    

    After we handle the UISearchBar search, we must make the request to Google Maps:

    - (void) searchCoordinatesForAddress:(NSString *)inAddress
    {
        //Build the string to Query Google Maps.
        NSMutableString *urlString = [NSMutableString stringWithFormat:@"http://maps.google.com/maps/geo?q=%@?output=json",inAddress];
    
        //Replace Spaces with a '+' character.
        [urlString setString:[urlString stringByReplacingOccurrencesOfString:@" " withString:@"+"]];
    
        //Create NSURL string from a formate URL string.
        NSURL *url = [NSURL URLWithString:urlString];
    
        //Setup and start an async download.
        //Note that we should test for reachability!.
        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
        NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    
        [connection release];
        [request release];
    }
    

    We must of course then handle the response of the GoogleMaps server ( Note: a lot of validations missing)

    //It's called when the results of [[NSURLConnection alloc] initWithRequest:request delegate:self] come back.
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
    {   
        //The string received from google's servers
        NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
        //JSON Framework magic to obtain a dictionary from the jsonString.
        NSDictionary *results = [jsonString JSONValue];
    
        //Now we need to obtain our coordinates
        NSArray *placemark  = [results objectForKey:@"Placemark"];
        NSArray *coordinates = [[placemark objectAtIndex:0] valueForKeyPath:@"Point.coordinates"];
    
        //I put my coordinates in my array.
        double longitude = [[coordinates objectAtIndex:0] doubleValue];
        double latitude = [[coordinates objectAtIndex:1] doubleValue];
    
        //Debug.
        //NSLog(@"Latitude - Longitude: %f %f", latitude, longitude);
    
        //I zoom my map to the area in question.
        [self zoomMapAndCenterAtLatitude:latitude andLongitude:longitude];
    
        [jsonString release];
    }
    

    Finally the function to zoom my map, which should by now be a trivial thing.

    - (void) zoomMapAndCenterAtLatitude:(double) latitude andLongitude:(double) longitude
    {
        MKCoordinateRegion region;
        region.center.latitude  = latitude;
        region.center.longitude = longitude;
    
        //Set Zoom level using Span
        MKCoordinateSpan span;
        span.latitudeDelta  = .005;
        span.longitudeDelta = .005;
        region.span = span;
    
        //Move the map and zoom
        [mapView setRegion:region animated:YES];
    }
    

    Hope this helps someone because the JSON part was a real pain to figure out, the library is not very well documented in my opinion, still it's very good.

    EDIT:

    Modified one method name to "searchCoordinatesForAddress:" because of @Leo question. I have to say that this method is good as a proof of concept but if you plan to download big JSON files , you will have to append to a NSMutableData object to hold all the query to the google server. ( remember that HTTP queries come by pieces . )