Objective c 对多个地址进行地理编码-CLGeocoder

Objective c 对多个地址进行地理编码-CLGeocoder,objective-c,mapkit,core-location,cllocationmanager,Objective C,Mapkit,Core Location,Cllocationmanager,我需要用CLGeocoder对大量地址进行地理编码,而不是谷歌API 我的问题是,我的代码只为下面数组中的第一个地址添加注释。但是,函数被调用的次数是适当的-在对所有地址调用函数之后,块只对第一个地址运行: - (void)mapPoints { NSString *foo = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"names%d", self.indexOfSchool] ofType:@

我需要用CLGeocoder对大量地址进行地理编码,而不是谷歌API

我的问题是,我的代码只为下面数组中的第一个地址添加注释。但是,函数被调用的次数是适当的-在对所有地址调用函数之后,块只对第一个地址运行:

- (void)mapPoints {
    NSString *foo = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"names%d", self.indexOfSchool] ofType:@"plist"];
    NSArray *description = [NSArray arrayWithContentsOfFile:foo];
    NSString *bar = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%d1", self.indexOfSchool] ofType:@"plist"];
    NSArray *details = [NSArray arrayWithContentsOfFile:bar];

    NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%d0", self.indexOfSchool] ofType:@"plist"];
    NSArray *addresses = [NSArray arrayWithContentsOfFile:path];
    self.saved = [NSMutableArray alloc] init];
    for (int q = 0; q < addresses.count; q+= 20) {
        [self annotate:[addresses objectAtIndex:q] detail:[details objectAtIndex:q] andDesc:[description objectAtIndex:q]];
    }
}

see updated annotate: method below...

。。。仍然拉出一张没有注释的空白地图——甚至第一张也没有。每次调用函数时,geocoder数组都有一个不同的内存地址,因此该块似乎正在工作。

每个
CLGeocoder
对象一次只能处理一个请求。尝试在
annotate
方法中创建一个新的
CLGeocoder
对象,而不是重用存储在属性中的单个对象。只要启用了ARC,您就应该没事了


请注意,苹果可能会限制您同时向其服务器发送的请求数量,因此,如果您执行大量请求,则可能需要限制未完成请求的数量。

您连续几次调用geocodeAddressString,但苹果的文档称

启动前向地理编码请求后,不要尝试 启动另一个正向或反向地理编码请求

因此,我认为现在发生的事情要么是当前请求在您发出新请求时被取消,要么是所有新请求都被忽略(如果一个请求已经在进行中)


作为一种解决方法,您可以对一个点进行地理编码,然后对完成块中的下一个点进行地理编码,或者创建地理编码器的多个实例

您一次只能运行一个地理编码请求,而不管您有多少个
CLGeocoder
实例。您必须使用上一个请求的完成块从开始启动另一个请求


此外,考虑到在短时间内对太多地址进行地理编码将达到其内部限制。在我的实验中,在大约50个请求(一个接一个)之后,框架在接下来的约60秒内拒绝处理新请求。

这是一个Xamarin伪代码,但它在本机中的工作原理应该与我必须首先转换为C的工作原理相同:

forloop()
{
    var geocoder = new CLGeocoder();
    var placemarks = await geocoder.GeocodeAddressAsync(address);
}

您需要保留对新geocoder实例的引用,否则它将在调用完成块之前被解除分配I'm use ARC-no retaining您仍然需要保留它。将其添加到数组中是最简单的方法OK。我遗漏了一些东西:将它添加到数组中,然后做什么?什么都不做,只是像现在一样调用geocode方法。将它添加到数组中会保留它,因此它不会在数组结束时被解除分配method@9fermat你能发布整个更新的
注释
方法吗?如果您仍然尝试使用
self.geocoder
而不是
geocoder
,您就会看到这种行为。还有,“实例而不是属性”是什么意思?我的意思是我没有使用
self.geocoder
,而只是使用
geocoder
-实例,而不是属性。@9fermat好的,无论如何请发布整个更新的方法。:-)这是正确的答案。非常感谢,您如何在前一个请求中启动新请求?@9fermat我将地址数组作为属性,并通过调用
[self-geocodeAddressAtIndex:0]启动它。然后在geocoder的completion块中,我只是递归调用了相同的方法,索引递增:
[self-geocodeAddressAtIndex:(I+1)]- (void)annotate:(NSString *)address detail:(NSString *)detail andDesc:(NSString *)description {
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder geocodeAddressString:address
             completionHandler:^(NSArray* placemarks, NSError* error) {
                 if (placemarks && placemarks.count > 0) {
                     CLPlacemark *topResult = [placemarks objectAtIndex:0];
                     MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
                     MKPointAnnotation *point = [[MKPointAnnotation alloc] init];
                     point.coordinate = placemark.coordinate;
                     point.title = description;
                     point.subtitle = [NSString stringWithFormat:@"%@ miles from origin", detail];
                     MKCoordinateRegion region = self.directionsView.region;
                     region.center = [(CLCircularRegion *)placemark.region center];
                     region.span.longitudeDelta /= 8.0;
                     region.span.latitudeDelta /= 8.0;
                     [self.directionsView addAnnotation:point];
                     NSLog(@"%@", point);
                     [self.directionsView setRegion:region animated:YES];
                 }
             }
 ];
    [self.saved addObject:geocoder];
    NSLog(@"%@", geocoder);
}
forloop()
{
    var geocoder = new CLGeocoder();
    var placemarks = await geocoder.GeocodeAddressAsync(address);
}