Map上的多个位置(使用MKMapItem和CLGeocoder)

我试图在MKMapItem显示多个位置。 我从CLGeocoder获取这些位置,不幸的是它只接受一个位置。 即使我通过一个NSArray它只是返回一个位置。

以下工作适用于单个位置,但不适用于多个位置。 我怎样才能对多个地点进行地理编码?

 Class mapItemClass = [MKMapItem class]; if (mapItemClass && [mapItemClass respondsToSelector:@selector(openMapsWithItems:launchOptions:)]) { NSArray *addresses = @[@"Mumbai",@"Delhi","Banglore"]; CLGeocoder *geocoder = [[CLGeocoder alloc] init]; [geocoder geocodeAddressString:@[addresses] completionHandler:^(NSArray *placemarks, NSError *error) { CLPlacemark *geocodedPlacemark = [placemarks objectAtIndex:0]; MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:geocodedPlacemark.location.coordinate addressDictionary:geocodedPlacemark.addressDictionary]; MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark]; [mapItem setName:geocodedPlacemark.name]; [MKMapItem openMapsWithItems:@[mapItem] launchOptions:nil]; }]; } 

回答你的问题,你是正确的,你一次只能发送一个地理编码请求。 实际上,“ CLGeocoder类参考”指出,我们的应用程序应该“最多发送一个用户操作的地理编码请求”。

所以,要做到这一点,你必须发送不同的请求。 但是这些请求(asynchronous运行)不应该同时运行。 所以,问题是如何使一系列asynchronous地理编码请求一个接一个地按顺序运行。

有很多不同的方式来解决这个问题,但是一个特别优雅的方法是使用一个并发的NSOperation子类,它不完成操作(即不执行isFinished KVN),直到地理编码请求的asynchronous完成块是调用。 (有关并发操作的信息,请参阅“ 并发编程指南”的“ 操作队列”一章的“为并发执行configuration操作”部分)。 然后只需将这些操作添加到串行操作队列。

另一种方法是使这个asynchronous地理编码请求以同步的方式运行,然后您可以将请求添加到串行队列中,请求将按顺序执行而不是并行执行。 您可以通过使用信号量来实现这一点,有效地指示分派的任务在地理编码请求完成之前不会返回。 你可以这样做:

 CLGeocoder *geocoder = [[CLGeocoder alloc]init]; NSMutableArray *mapItems = [NSMutableArray array]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; queue.maxConcurrentOperationCount = 1; // make it a serial queue NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{ [MKMapItem openMapsWithItems:mapItems launchOptions:nil]; }]; NSArray *addresses = @[@"Mumbai, India", @"Delhi, India", @"Bangalore, India"]; for (NSString *address in addresses) { NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) { if (error) { NSLog(@"%@", error); } else if ([placemarks count] > 0) { CLPlacemark *geocodedPlacemark = [placemarks objectAtIndex:0]; MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:geocodedPlacemark.location.coordinate addressDictionary:geocodedPlacemark.addressDictionary]; MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark]; [mapItem setName:geocodedPlacemark.name]; [mapItems addObject:mapItem]; } dispatch_semaphore_signal(semaphore); }]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); }]; [completionOperation addDependency:operation]; [queue addOperation:operation]; } [[NSOperationQueue mainQueue] addOperation:completionOperation]; 

或者,你也可以使用更传统的模式。 例如,您可以编写一个执行单个地理编码请求的方法,并在完成块中启动下一个请求,并重复该过程,直到发出所有请求。

寻找Swift解决scheme的伙计们:

 func getCoordinate( addressString : String, completionHandler: @escaping(CLLocationCoordinate2D, NSError?) -> Void ){ let geocoder = CLGeocoder() geocoder.geocodeAddressString(addressString) { (placemarks, error) in if error == nil { if let placemark = placemarks?[0] { let location = placemark.location! completionHandler(location.coordinate, nil) return } } completionHandler(kCLLocationCoordinate2DInvalid, error as NSError?) } } 

感谢苹果。 官方文档链接

您可以通过以下方式使用该代码段来处理多个地址:

 let address = ["India","Nepal"] for i in 0..<address.count { getCoordinate(addressString: address[i], completionHandler: { (location, error) in //Do your stuff here. For eg Adding annotation or storing location }) }