2

次のようなメソッドがあります。

-(NSString *)getCityFromLocation:(CLLocation *)location {

    __block NSString *city;

    CLGeocoder *geocoder = [[CLGeocoder alloc] init];

    [geocoder reverseGeocodeLocation: location completionHandler:
     ^(NSArray *placemarks, NSError *error) {

         //Get address
         CLPlacemark *placemark = [placemarks objectAtIndex:0];

         city = [placemark.addressDictionary objectForKey:@"City"];

         NSLog(@"city 1: %@", city);

     }];

    return city;
}

そして、私はそれを次のように呼びます:

NSString *city = [self getCityFromLocation:currentLocation];

NSLog(@"city 2: %@", city);

NSLog では、次のようになります。

city 2: (null)
city 1: London

問題は明らかです。ブロックを実行する前に戻ってきます。ブロックによって生成された値を返すことができる場合、これを意図したとおりに機能させるにはどうすればよいですか?

4

3 に答える 3

1

ここで使用したような非同期メソッドは、reverseGeocodeLocation:通常、非常に正当な理由があります。完了するまでに時間がかかります。その観点から、最初に設計を検討し、非同期メソッドを同期的に使用する必要があるかどうかを判断する必要があります。

これを行う必要があると判断した場合、1 つの解決策はセマフォを使用することです。(マニュアルのセクション 3 の GCD の一部)をreverseGeocodeLocation:使用してセマフォを作成する呼び出しの前。dispatch_semaphore_create次に、ブロック内で文字列の準備ができていることdispatch_semaphore_signalを示し、ブロックの外でdispatch_semaphore_wait文字列の準備ができるまでブロックします。

これを行うためにコードを変更し、回答に直接入力して実行しませんでした:

#include <dispatch/dispatch.h>

-(NSString *)getCityFromLocation:(CLLocation *)location
{

   __block NSString *city;

   dispatch_semaphore_t sema = dispatch_semaphore_create(0);

   CLGeocoder *geocoder = [[CLGeocoder alloc] init];

   [geocoder reverseGeocodeLocation: location completionHandler:
      ^(NSArray *placemarks, NSError *error)
      {
         //Get address
         CLPlacemark *placemark = [placemarks objectAtIndex:0];

         city = [placemark.addressDictionary objectForKey:@"City"];
         dispatch_semaphore_signal(sema); // string is ready
      }
   ];

   dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); // wait for string
   dispatch_release(sema); // if you are using ARC & 10.8 this is NOT needed
   return city;
}

しかし、真剣に、これがあなたがすべきことかどうかを慎重に検討してください.

HTH。

于 2013-04-23T10:15:58.373 に答える