Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CLGeocoder ever return one placemark

Tags:

ios

clgeocoder

I want to revive this and this question because the problem still persists for me, so I'm writing a new question.

This is my code:

- (SVGeocoder*)initWithParameters:(NSMutableDictionary*)parameters completion:(SVGeocoderCompletionHandler)block {
self = [super init];

self.operationCompletionBlock = block;

Class cl = NSClassFromString(@"CLGeocoder");
if (cl != nil)
{
    if (self.geocoder_5_1 == nil) {
        self.geocoder_5_1 = [[cl alloc] init];
    }

    NSString *address = [parameters objectForKey:kGeocoderAddress];
    [self.geocoder_5_1 geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
        NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
        SVPlacemark *placemark;
        NSLog(@"placemarks[count] = %i", [placemarks count]);
        for (CLPlacemark *mark in placemarks) {
            placemark = [[SVPlacemark alloc] initWithPlacemark:mark];
            [svplacemarks addObject:placemark];
        }

        self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
    }];

}
else
{
    self.operationRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://maps.googleapis.com/maps/api/geocode/json"]];
    [self.operationRequest setTimeoutInterval:kSVGeocoderTimeoutInterval];

    [parameters setValue:@"true" forKey:kGeocoderSensor];
    [parameters setValue:[[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode] forKey:kGeocoderLanguage];
    [self addParametersToRequest:parameters];

    self.state = SVGeocoderStateReady;
}
return self;
}

It is my personal version (quite rough) of SVGeocoder using CLGeocoder for forward geocoding with retrocompatibility for iOS < 5.1

I use this solution because of the Google terms which prevent the use of the maps API without showing the result on a Google map.

The problem is the same one from the previously mentioned questions: CLGeocoder returns only one placemark and the log prints a nice

"placemarks[count] = 1".

My question is, does anyone know if there is another way to retrieve forward geocoding, or some other magic thing (the Apple map app shows multiple markers for the same query I do, "via roma", for example) ?


EDIT FOR ROB'S SOLUTION

Class mkLocalSearch = NSClassFromString(@"MKLocalSearch");

if (mkLocalSearch != nil)
{
    NSString *address = [parameters objectForKey:kGeocoderAddress];
    MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];

    request.region = MKCoordinateRegionForMapRect(MKMapRectWorld);

    request.naturalLanguageQuery = address;

    MKLocalSearch *localsearch = [[MKLocalSearch alloc] initWithRequest:request];
    [localsearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {

        NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
        SVPlacemark *placemark;
        NSLog(@"response.mapItems[count] = %i", [response.mapItems count]);

        for (MKMapItem *item in response.mapItems)
        {
            placemark = [[SVPlacemark alloc] initWithPlacemark:item.placemark];
            [svplacemarks addObject:placemark];
        }

        self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
    }];
}

This is an interesting solution that gives another point of view. Unfortunately, even if I set the region to worldwide, I still get a nice log

response.mapItems[count] = 1

The query was "via roma", which is a very common street name in Italy, so much so that I think we can find it in practically any Italian city.

Maybe I'm doing something wrong?


EDIT 2 - New Test:

convert World Rect to CLRegion, code from here

    NSString *address = [parameters objectForKey:kGeocoderAddress];

    // make a conversion from MKMapRectWorld to a regular CLRegion
    MKMapRect mRect = MKMapRectWorld;
    MKMapPoint neMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), mRect.origin.y);
    MKMapPoint swMapPoint = MKMapPointMake(mRect.origin.x, MKMapRectGetMaxY(mRect));

    float ewDelta= neMapPoint.x - swMapPoint.x;
    float nsDelta= swMapPoint.y - neMapPoint.y;

    MKMapPoint cMapPoint = MKMapPointMake(ewDelta / 2 + swMapPoint.x, nsDelta / 2 + neMapPoint.y);

    CLLocationCoordinate2D neCoord = MKCoordinateForMapPoint(neMapPoint);
    CLLocationCoordinate2D swCoord = MKCoordinateForMapPoint(swMapPoint);

    CLLocationCoordinate2D centerCoord = MKCoordinateForMapPoint(cMapPoint);

    CLLocationDistance diameter = [self getDistanceFrom:neCoord to:swCoord];

// i don't have the map like showed in the example so i'm trying to center the search area to the hypothetical center of the world
    CLRegion *clRegion = [[CLRegion alloc] initCircularRegionWithCenter:centerCoord radius:(diameter/2) identifier:@"worldwide"];
    [self.geocoder_5_1 geocodeAddressString:address inRegion: clRegion completionHandler:^(NSArray *placemarks, NSError *error) {
        NSMutableArray *svplacemarks = [NSMutableArray arrayWithCapacity:1];
        SVPlacemark *placemark;
        NSLog(@"placemarks[count] = %i", [placemarks count]);
        for (CLPlacemark *mark in placemarks) {
            placemark = [[SVPlacemark alloc] initWithPlacemark:mark];
            [svplacemarks addObject:placemark];
        }

        self.operationCompletionBlock([NSArray arrayWithArray:svplacemarks],nil,error);
    }];

... and I get the usual "placemark [count] = 1"

like image 493
Alex75 Avatar asked Apr 03 '13 16:04

Alex75


1 Answers

Obviously, CLGeocoder will return multiple placemarks if the address gets multiple hits (i.e. the region is large enough such that the simple street address is ambiguous), but frequently it will find just the one match if the region is small enough or if the supplied address is unique enough.

While it's not a general purpose solution, effective iOS 6.1, you have MKLocalSearch, which does a more general lookup (including names of businesses, etc.):

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

MKLocalSearch *localsearch = [[MKLocalSearch alloc] initWithRequest:request];
[localsearch startWithCompletionHandler:^(MKLocalSearchResponse *response, NSError *error) {
    for (MKMapItem *item in response.mapItems)
    {
        Annotation *annotation = [[Annotation alloc] initWithPlacemark:item.placemark];
        annotation.title = item.name;
        annotation.phone = item.phoneNumber;
        annotation.subtitle = item.placemark.addressDictionary[(NSString *)kABPersonAddressStreetKey];
        [self.mapView addAnnotation:annotation];
    }
}];

I guess it all depends upon what sort of multiple hits you're expecting to receive.

like image 90
Rob Avatar answered Oct 04 '22 14:10

Rob