CLGeocoder 曾经返回一个地标

Posted

技术标签:

【中文标题】CLGeocoder 曾经返回一个地标【英文标题】:CLGeocoder ever return one placemark 【发布时间】:2013-04-03 16:40:37 【问题描述】:

我想重新提出this 和this 的问题,因为我的问题仍然存在,所以我正在写一个新问题。

这是我的代码:

- (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;

这是我个人的 SVGeocoder 版本(相当粗糙),使用 CLGeocoder 进行前向地理编码,具有 ios

我使用此解决方案是因为 Google 条款阻止使用地图 API 而不在 Google 地图上显示结果。

问题与前面提到的问题相同:CLGeocoder 只返回一个地标,日志打印出一个不错的

“地标[计数] = 1”。

我的问题是,有谁知道是否有另一种方法可以检索前向地理编码或其他一些神奇的东西(Apple 地图应用程序显示我执行的同一查询的多个标记,例如“通过 roma”)?


编辑 ROB 的解决方案

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);
    ];

这是一个有趣的解决方案,它提供了另一种观点。不幸的是,即使我将区域设置为全球,我仍然会得到一个不错的日志

response.mapItems[count] = 1

查询是“via roma”,这是意大利非常常见的街道名称,以至于我认为我们几乎可以在任何意大利城市找到它。

也许我做错了什么?


编辑 2 - 新测试:

将World Rect转换为CLRegion,代码来自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);
    ];

...我得到通常的“地标 [count] = 1”

【问题讨论】:

【参考方案1】:

显然,CLGeocoder 将在地址获得多次点击时返回多个地标(即区域足够大以至于简单的街道地址不明确),但如果区域足够小,它通常只会找到一个匹配项或者如果提供的地址足够独特。

虽然它不是通用解决方案,但适用于 iOS 6.1,您有 MKLocalSearch,它会进行更通用的查找(包括企业名称等):

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];
    
];

我想这完全取决于您期望收到什么样的多次点击。

【讨论】:

感谢 Rob 的回答。该应用程序的目的类似于卫星导航器。我将编辑我的帖子以展示您的解决方案的实施。 无论我使用哪种解决方案(CLGeoCoderMKLocalSearch),我总是只得到一个结果。我在德国柏林,在搜索“San”时,我得到的是“San Diego, CA”而不是“San Francisco, CA”。我希望他们两个(地球上有很多 San...s...) @Julian - 我同意。这些都没有返回详尽的列表。使用 CLGeocoder 我不会看到超过 1 或 2 个条目。这感觉像是一种“最佳猜测”方法,返回两三个条目。使用MKLocalSearch,您将获得更多点击(例如,尝试在任何特定城市搜索“餐厅”,您将获得餐厅列表),但这绝不是一个详尽的列表(将区域更改一小部分很少,你最终会得到一个非常不同的结果列表)。 是的。经过更多的阅读、测试和印象,我很确定它真的只搜索兴趣点,因为大城市总是有自己的“地址”,你会找到它们。地址查找肯定需要一些不同的东西,据我所知,他们没有内置任何东西......【参考方案2】:

CLGeocoder 确实会为某些地址返回多个地标。我发现的一个例子是“Herzel 13, Haifa, Israel”。我使用geocodeAddressDictionary:completionHandler: 方法,得到相同的两个地址结果(可以设置为街道/城市/国家,也可以设置为街道 - 结果相同)。

很难找到这样的例子,当然它们将来可能会改变。出于某种原因,Apple 地图应用会显示“您的意思是...”对话框以获取更多地址。

【讨论】:

是的......问题只是:“苹果是怎么做到的?”直到今天我没有发现任何回应

以上是关于CLGeocoder 曾经返回一个地标的主要内容,如果未能解决你的问题,请参考以下文章

为啥将 CLGeocoder 与“地标”数组一起使用?

CLGeoCoder 未按正确顺序附加地标

测试 CLGeocoder geocodeAddressString 方法地标始终为零

按最近位置排序 CLGeoCoder geocodeAddressString 的结果

在 iOS 中使用 CLGeocoder 进行转发地理编码,为某些位置的位置返回 null

CLGeocoder() 意外返回 nil