CLGeocoder ever return one placemark
Asked Answered
T

2

10

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"

Tempestuous answered 3/4, 2013 at 16:40 Comment(0)
A
5

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.

Antiphon answered 3/4, 2013 at 19:50 Comment(4)
Thanks Rob for the answer. The aim of the application is similar to that of a satellite navigator. I'll edit my post to show the implementation of your solution.Tempestuous
Regardless of which solution I'm using (wether CLGeoCoder or MKLocalSearch) I'm always getting only one result. I'm in Berlin, Germany and when searching for "San" I'm getting "San Diego, CA" and not "San Francisco, CA". I'd expect both of them (There are plenty of San...s on earth...)Genetics
@Julian - I agree. Neither of these return exhaustive lists. With CLGeocoder I won't see more than 1 or 2 entries. It feels like a "best guess" approach, returning two or three entries. With MKLocalSearch, you'll get many more hits (e.g. try searching for "restaurant" in any particular city and you'll get a list of restaurants), but by no means is it an exhaustive list (change the region a fraction little and you can end up with a very different list of results).Antiphon
Yep. After a bit more reading and tests and impressions I'm quite certain it really only searches points of interests, since big cities always have their own "address", you'll find them. An address lookup would definitely need something different and as far as I can tell their's nothing built in...Genetics
A
0

There are some addresses for which CLGeocoder does return multiple placemarks. One example I've found is "Herzel 13, Haifa, Israel". I use the geocodeAddressDictionary:completionHandler: method, and get the same 2 results for the address (it can be set either as street/city/country, or just as a street - the results are the same).

It's just pretty hard to find such examples, and they may change in the future of course. For some reason, the Apple maps app shows the "Did you mean..." dialog for many more addresses.

Adiaphorism answered 11/4, 2013 at 7:11 Comment(1)
yep... the question is just: "How did apple make that?" Until today i found no responseTempestuous

© 2022 - 2024 — McMap. All rights reserved.