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.
You create an MKLocalSearch. Request object when you want to search for map locations based on a natural language string. For example, if your interface allows the user to type in addresses, place the typed text in this object and pass it to an MKLocalSearch object to begin the search process.
MapKit is a powerful API available on iOS devices that makes it easy to display maps, mark locations, enhance with custom data and even draw routes or other shapes on top.
This maybe the easiest method. It uses apple servers for geocoding. Sometimes the apple servers provide better response than google. And soon (in IOS 6.1) the google maps will be completely out of IOS. So it is good if the app stays inside the apples provided features.
-(void)searchBarSearchButtonClicked:(UISearchBar *)theSearchBar { [theSearchBar resignFirstResponder]; CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder geocodeAddressString:theSearchBar.text completionHandler:^(NSArray *placemarks, NSError *error) { //Error checking CLPlacemark *placemark = [placemarks objectAtIndex:0]; MKCoordinateRegion region; region.center.latitude = placemark.region.center.latitude; region.center.longitude = placemark.region.center.longitude; MKCoordinateSpan span; double radius = placemark.region.radius / 1000; // convert to km NSLog(@"[searchBarSearchButtonClicked] Radius is %f", radius); span.latitudeDelta = radius / 112.0; region.span = span; [theMapView setRegion:region animated:YES]; }]; }
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 . )
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With