对多个位置进行地理编码 – 了解何时调用“所有”完成块

我正在使用CoreLocation的地理编码器来获取多个地图项的CLLocation坐标。 地理编码器在完成时为每个项目调用完成块。

所有包含asynchronous地理编码调用的调用完成后,如何创build一个类似的块function? (我可以使用手动计数器,但必须有一个更优雅的解决scheme)

这是我迄今为止的地理编码function。 它通过一系列位置项目进行循环,并为每个项目启动一个新的地理编码过程。

-(void)geoCodeAllItems { for (EventItem* thisEvent in [[EventItemStore sharedStore] allItems]) { if (![thisEvent eventLocationCLLocation]){ //Only geocode if the item has no location data yet CLGeocoder *geocoder = [[CLGeocoder alloc]init]; [geocoder geocodeAddressString:[thisEvent eventLocationGeoQuery] completionHandler:^(NSArray *placemarks, NSError *error) { if (error){ NSLog(@"\t Geo Code - Error - Failed to geocode"; return; } if (placemarks) { if ([placemarks count] > 1) NSLog(@"\t Geo Code - Warning - Multiple Placemarks (%i) returned - Picking the first one",[placemarks count]); CLPlacemark* placemark = [[CLPlacemark alloc]initWithPlacemark:[placemarks objectAtIndex:0]]; CLLocationCoordinate2D placeCoord = [[placemark location]coordinate]; [thisEvent setEventLocationCLLocation:[[CLLocation alloc]initWithLatitude:placeCoord.latitude longitude:placeCoord.longitude]]; [[EventItemStore sharedStore] saveItems]; } else { NSLog(@"\t Geo Code - Error - No Placemarks decoded"); } }]; geocoder = nil; } } } 

这基本上工作,但由于asynchronous的方式,我不知道什么时候所有的地理编码活动终于结束。

我的感觉是,我要么为此创build一个块,要么使用Grand Central Dispatch,但我不确定。 我感谢任何帮助,find正确的方法。

您可以使用GCD调度组来执行此操作。 另外,我认为你可以用一个CLGeocoder做出多个请求。

由于我们可能根本不需要创build组和地理编码器,所以我们将懒惰地创build它们:

 -(void)geocodeAllItems { dispatch_group_t group = NULL; CLGeocoder *geocoder = nil; 

我们遍历这些项目,跳过那些已经进行了地理编码的项目:

  for (EventItem *item in [[EventItemStore sharedStore] allItems]) { if (item.eventLocationCLLocation) continue; 

现在我们已经find了一个需要地理编码的地方,如果需要我们创build地理编码器和调度组:

  if (!geocoder) { geocoder = [[CLGeocoder alloc] init]; group = dispatch_group_create(); } 

我们将使用一个辅助方法来对这个项目进行地理编码:

  [self geocodeItem:item withGeocoder:geocoder dispatchGroup:group]; } 

现在我们已经完成了所有项目,我们将检查是否对任何项目进行了地理编码:

  if (group) { 

如果我们对任何一个进行了地理编码,那么调度组中有块。 我们将要求小组在变空时执行通知块:

  dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"note: all geocoding requests have completed"); }); 

最后,我们需要释放组以平衡由dispatch_group_create返回的+1保留计数:

  dispatch_release(group); } } 

以下是仅对一个项目进行地理编码的帮助程序方法:

 - (void)geocodeItem:(EventItem *)item withGeocoder:(CLGeocoder *)geocoder dispatchGroup:(dispatch_group_t)group { 

我们“进入”这个小组。 这会自动增加组的成员计数器:

  dispatch_group_enter(group); 

然后我们可以开始地理编码:

  [geocoder geocodeAddressString:item.eventLocationGeoQuery completionHandler:^(NSArray *placemarks, NSError *error) { if (error) { NSLog(@"error: geocoding failed for item %@: %@", item, error); } else { if (placemarks.count == 0) { NSLog(@"error: geocoding found no placemarks for item %@", item); } else { if (placemarks.count > 1) { NSLog(@"warning: geocoding found %u placemarks for item %@: using the first", item, placemarks.count); } CLPlacemark* placemark = placemarks[0]; thisEvent.eventLocationCLLocation = placemarks[0].location; [[EventItemStore sharedStore] saveItems]; } } 

在地理编码完成块中,完成所有工作之后,我们“离开”组,从而递减其成员计数:

  dispatch_group_leave(group); }]; } 

当成员计数变为零时,组将执行我们在geocodeAllItems结尾添加的通知块。

看看NSOperationQueue使用的NSBlockOperation

创build一个NSBlockOperation,然后将所有单独的任务添加为执行块addExecutionBlock:。 设置你的完成块setCompletionBlock:它在NSOperation超类中,当所有的任务完成时它会被调用。 他们默认情况下不会在主线程上运行,所以如果你想要在主线程上执行你的完成块,你必须明确地告诉它这样做。 将NSBlockOperation添加到NSOperationQueue addOperation:(NSOperation *)operation

操作队列上的“并发指南”页面

推荐:WWDC 2012video会议225(跳至16:55)

Interesting Posts