对许多地址进行地理编码 - CLGeocoder
Posted
技术标签:
【中文标题】对许多地址进行地理编码 - CLGeocoder【英文标题】:Geocoding many addresses - CLGeocoder 【发布时间】:2013-11-07 14:23:49 【问题描述】:我需要使用 CLGeocoder 对大量地址进行地理编码,不是 Google 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...
以下是我的日志的显示方式:
here
here
here
here
.
..
...
....
<MKPointAnnotation: 0x16fc12e0>
因此,虽然该函数是通过循环调用的,但该块并未针对除第一个结果之外的任何结果运行。
我知道我的地址很好。这不适用于任何数量 (>1) 的函数调用。
循环中的 += 20
与仅绘制一个点无关:这对 ++
也不起作用(也有大约 200 个结果)。
我对块相当陌生,所以希望这是一个简单的解决方法。非常感谢任何帮助!
编辑 改为这样做:
- (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);
... 仍然拉出一张没有注释的空白地图——甚至不是第一个。每次调用该函数时,地理编码器数组都有不同的内存地址,因此该部分似乎正在工作。
【问题讨论】:
我认为你应该在 GCD 中使用信号量。 【参考方案1】:您连续几次调用 geocodeAddressString,但苹果的文档说
在发起转发地理编码请求后,不要尝试 发起另一个正向或反向地理编码请求。
所以我认为正在发生的事情是当您提出新请求时当前请求被取消,或者如果一个新请求已经在进行中,则所有新请求都将被忽略。
作为一种解决方法,您可以对一个点进行地理编码,然后对完成块中的下一个点进行地理编码,或者创建地理编码器的多个实例
【讨论】:
您需要保留对新地理编码器实例的引用,否则它将在调用完成块之前被释放 我正在使用 ARC - 没有保留 您仍然需要保留它。将其添加到数组将是最简单的方法 好的。我错过了一些东西:将它添加到数组中然后做什么? 没什么,只是像现在一样调用 geocode 方法。将它添加到数组中会保留它,因此它不会在方法结束时被释放【参考方案2】:每个CLGeocoder
对象一次只能处理一个请求。尝试在 annotate
方法中创建一个新的 CLGeocoder
对象,而不是重用存储在属性中的单个对象。只要您启用了 ARC,就应该没问题。
请注意,Apple 可能会限制您同时发送到其服务器的请求数量,因此如果您处理大量未完成的请求,您可能需要限制这些请求的数量。
【讨论】:
@9fermat 你能发布整个更新的annotate
方法吗?如果您仍在尝试使用self.geocoder
而不是geocoder
,您会看到这种行为。另外,“实例而不是属性”是什么意思?
我的意思是我没有使用self.geocoder
,而只是使用geocoder
——实例,而不是属性。
@9fermat 好的,无论如何请发布整个更新的方法。 :-)
这是真正的答案。非常感谢【参考方案3】:
无论您有多少个CLGeocoder
实例,您一次只能运行一个地理编码请求。您将不得不从前一个请求的完成块开始另一个请求。
另外,请注意,在短时间内对过多地址进行地理编码将达到其内部限制。在我的实验中,在大约 50 个请求(一个接一个)之后,框架拒绝在接下来的大约 60 秒内处理新请求。
【讨论】:
如何在前一个请求中开始一个新请求? @9fermat 我将地址数组作为属性,并通过调用[self geocodeAddressAtIndex:0];
来启动它。然后在地理编码器的完成块中,我只是递归地调用具有递增索引的相同方法:[self geocodeAddressAtIndex:(i + 1)];
【参考方案4】:
这是一个 Xamarin 伪代码,但它应该在本机中工作,因为我必须首先转换为 C#:
forloop()
var geocoder = new CLGeocoder();
var placemarks = await geocoder.GeocodeAddressAsync(address);
【讨论】:
以上是关于对许多地址进行地理编码 - CLGeocoder的主要内容,如果未能解决你的问题,请参考以下文章