6

で複数の場所を表示しようとしていますMKMapItem。私はそれらの場所をから取得していますがCLGeocoder、残念ながら1つの場所しか受け入れません。私が渡したとしても、NSArrayそれはただ1つの場所を返します。

以下は、単一の場所では正常に機能しますが、複数の場所では機能しません。複数の場所をジオコーディングするにはどうすればよいですか?

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];
    }];
}
4

2 に答える 2

13

あなたの質問への回答として、一度に 1 つのジオコード リクエストしか送信できないことは正しいです。実際、CLGeocoder クラス リファレンスでは、アプリは「1 つのユーザー アクションに対して最大 1 つのジオコーディング リクエストを送信する」必要があると述べています。

したがって、これを行うには、個別のリクエストを送信する必要があります。ただし、これらの要求 (非同期で実行される) は同時に実行されるべきではありません。したがって、問題は、一連の非同期ジオコード リクエストを次々と順番に実行する方法です。

これに取り組むにはさまざまな方法がありますが、特に洗練されたアプローチの 1 つは、ジオコード リクエストの非同期完了ブロックが呼び出されるまでNSOperation操作を完了しない (つまり、 isFinishedKVN を実行しない) 同時サブクラスを使用することです。(同時操作の詳細については、「同時実行プログラミング ガイド」の「操作キュー」の章の「同時実行のための操作の構成」セクションを参照してください)。次に、それらの操作をシリアル操作キューに追加するだけです。

もう 1 つの方法は、この非同期ジオコード リクエストを同期的に動作させることです。その後、リクエストをシリアル キューに追加するだけで、リクエストは並列ではなく順次実行されます。これは、セマフォを使用して、ディスパッチされたタスクに、ジオコード リクエストが完了するまで戻らないように効果的に指示することで実現できます。次のようにできます。

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];

あるいは、より伝統的なパターンを採用することもできます。たとえば、単一のジオコード リクエストを実行し、完了ブロックで次のリクエストを開始し、すべてのリクエストが行われるまでそのプロセスを繰り返すメソッドを作成できます。

于 2013-01-07T15:08:57.557 に答える