地图上的多个位置(使用MKMapItem和CLGeocoder)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了地图上的多个位置(使用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 Class Reference说我们的应用程序应该“为任何一个用户操作发送最多一个地理编码请求”。
因此,要执行此操作,您必须发送单独的请求。但是这些请求(异步运行)不应该同时运行。因此,问题是如何使一系列异步地理编码请求一个接一个地顺序运行。
有很多不同的方法可以解决这个问题,但一种特别优雅的方法是使用并发的NSOperation
子类,它不会完成操作(即不执行isFinished
KVN),直到地理编码请求的异步完成块为止。调用。 (有关并发操作的信息,请参阅“并发编程指南”的Operation Queue章节的“配置并发执行操作”部分)。然后只需将这些操作添加到串行操作队列中。
另一种方法是使此异步地理编码请求以同步方式运行,然后您可以将请求添加到串行队列,并且请求将按顺序执行而不是并行执行。您可以通过使用信号量来实现此目的,有效地指示调度任务在地理编码请求完成之前不返回。你可以这样做:
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解决方案的人:
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?)
}
}
感谢Apple。官方文件link
您可以通过以下方式使用代码段来获取多个地址:
let address = ["India","Nepal"]
for i in 0..<address.count {
getCoordinate(addressString: address[i], completionHandler: { (location, error) in
//Do your stuff here. For e.g. Adding annotation or storing location
})
}
以上是关于地图上的多个位置(使用MKMapItem和CLGeocoder)的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 中将 CLLocation 转换为 MKMapItem