Objective-C - Search for streets based on user-entered query
Asked Answered
C

3

8

I want to allow the users to search for a street name and have the results displayed in a UITableView. For the moment the region is not important, it can be from any region.

I could not find any relevant example in my searches and I don't know if I should use CLLocation or MKLocalSearch.

Based on docs, I should use MKLocalSearch:

Although local search and geocoding are similar, they support different use cases. Use geocoding when you want to convert between map coordinates and a structured address, such as an Address Book address. Use local search when you want to find a set of locations that match the user’s input.

But I have tried both methods and it gives me only 1 result (even-though there is an NSArray returned.

This is the CLGeocoder approach:

CLGeocoder *geocoding = [[CLGeocoder alloc] init];
[geocoding geocodeAddressString:theTextField.text completionHandler:^(NSArray *placemarks, NSError *error) {
    if (error) {
        NSLog(@"%@", error);
    } else {
        NSLog(@"%i", [placemarks count]);
        for(CLPlacemark *myStr in placemarks) {
            NSLog(@"%@", myStr);
    }
    }
}];

And this is my MKLocalSearch try:

MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = theTextField.text;
request.region = self.region;

localSearch = [[MKLocalSearch alloc] initWithRequest:request];

[localSearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error){

    if (error != nil) {
        [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Map Error",nil)
                                    message:[error localizedDescription]
                                   delegate:nil
                          cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] show];
        return;
    }

    if ([response.mapItems count] == 0) {
        [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"No Results",nil)
                                    message:nil
                                   delegate:nil
                          cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] show];
        return;
    }
    self.streets = response;
    [self.streetsTableView reloadData];
}];

MKLocalSearch seems to return more than 1 response in some cases, but these are related to places not street names searches.

Thanks in advance.

Carvey answered 26/5, 2015 at 14:47 Comment(4)
did you try setting region to nil? or can you share more details on your self.region?Jingo
I have a MapView and I am using MapView.region as self.regionCarvey
from my experience MKLocalSearch is very primitive. Would you be opposed to using Google Places API for any reason?Warthman
google has a more useful api, MKLocalSearch is for a simple tasks onlyCommendam
W
4

This is the closest I could get. This involves using google places API Web Service.

Note: You could probably use their Google Maps API, etc. I am sure there are other ways to get this information from the various Google APIs.

 NSURL *googlePlacesURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/place/autocomplete/json?input=%@&location=%f,%f&sensor=true&key=API_KEY", formattedSearchText, location.coordinate.latitude,
                                                   location.coordinate.longitude]];

The response is a JSON object. Convert it to a dictionary.

 NSDictionary *response = [NSJSONSerialization JSONObjectWithData:_googlePlacesResponse
                                                                    options:NSJSONReadingMutableContainers error:&error];

if([[response objectForKey:@"status"] isEqualToString:@"OK"])
{
    NSArray *predictions = [response objectForKey:@"predictions"];
    for(NSDictionary *prediction in predictions)
    {
        NSArray *addressTypes = [prediction objectForKey:@"types"];
        if([addressTypes containsObject:@"route"])
        {
            //This search result contains a street name. 
            //Now get the street name.
            NSArray *terms = [prediction objectForKey:@"terms"];
            NSDictionary *streetNameKeyValuePair = [terms objectAtIndex:0];
            NSLog(@"%@",[streetNameKeyValuePair objectForKey@"value"]);
        }
    }
}

The possible types seem to be

  • Route -> Street name
  • Locality -> City/location name
  • Political -> State, etc
  • Geocode -> lat/long available
  • You could populate the table view with those predictions that ONLY contain route as an address type. This could work.

    Warthman answered 4/6, 2015 at 20:1 Comment(1)
    Yep, that's the way. I have done the same, before reading your answer :). This one helped me: https://mcmap.net/q/1469556/-mklocalsearch-not-finding-obvious-resultsCarvey
    H
    2

    CLGeocoder simply returns address format. Slap this in your code and play with the contents of mapitems

    MKLocalSearchRequest *request = [MKLocalSearchRequest new];
    request.naturalLanguageQuery = @"Pizza";
    request.region = MKCoordinateRegionMake(location.coordinate, MKCoordinateSpanMake(.01, .01));
    MKLocalSearch *search = [[MKLocalSearch alloc]initWithRequest:request];
    [search startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
        NSArray *mapItems = response.mapItems;
        for (MKMapItem *mapItem in mapItems) {
            MKPointAnnotation *point = [MKPointAnnotation new];
            point.coordinate = mapItem.placemark.coordinate;`
        }
    }];
    
    Hag answered 2/6, 2015 at 17:8 Comment(0)
    I
    1

    The array returned contains mapItems, you can iterate over the array to pull out all the mapItems like this:

    myMatchingItems = [[NSMutableArray alloc] init];
    for (MKMapItem *item in response.mapItems){
                        [myMatchingItems addObject:item];
        }
    

    Each mapItem.placemark.thoroughfare contains the Street of the location that was found.

    Investigation answered 4/6, 2015 at 20:22 Comment(0)

    © 2022 - 2024 — McMap. All rights reserved.