Отвечая на ваш вопрос, вы правы в том, что вы можете отправить только один запрос геокодирования за раз. Фактически, справочник по классам CLGeocoder говорит, что наши приложения должны «отправлять не более одного запроса геокодирования для любого действия пользователя».
Итак, для этого необходимо отправлять отдельные запросы. Но эти запросы (которые выполняются асинхронно) не должны выполняться одновременно. Итак, вопрос в том, как сделать так, чтобы серия асинхронных запросов геокодирования выполнялась последовательно, один за другим.
Есть много разных способов решить эту проблему, но один особенно элегантный подход заключается в использовании параллельного подкласса NSOperation
, который не завершает операцию (т. е. не выполняет isFinished
КВН) до тех пор, пока не будет получен блок асинхронного завершения запроса геокодирования. называется. (Информацию о параллельных операциях см. в разделе Настройка операций для параллельного выполнения в Очередь операций главы Руководство по программированию с параллельным доступом). Затем просто добавьте эти операции в очередь последовательных операций.
Другой подход заключается в том, чтобы заставить этот асинхронный запрос геокода вести себя синхронно, а затем вы можете просто добавить запросы в последовательную очередь, и запросы будут выполняться последовательно, а не параллельно. Этого можно добиться с помощью семафоров, фактически предписывая отправленной задаче не возвращаться до завершения запроса геокодирования. Вы можете сделать это так:
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];
В качестве альтернативы вы можете использовать и более традиционные шаблоны. Например, вы можете написать метод, который выполняет один запрос геокодирования, а в блоке завершения инициирует следующий запрос и повторяет этот процесс до тех пор, пока не будут выполнены все запросы.
person
Rob
schedule
07.01.2013