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. 但当时它没有调用。它会在什么时候调用reverse Geocode process get complete。但 city立即获得回报。这就是为什么你会这样。

您可以通过将其分配给本地属性来解决。当完成块被执行时。所以代码应该是。

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

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

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

     }];
于 2013-04-23T10:04:57.200 回答
1

与其在内部创建块getCityFromLocation,不如将getCityFromLocation其作为一个块(我的意思是回调方法)。

typedef void (^Callback)(BOOL isSuccess, id object);

-(void)getCityFromLocation:(Callback)iCallback
{
    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);
      iCallback(YES,city);

   }];

}
于 2013-04-23T10:06:56.880 回答
1

异步方法,例如reverseGeocodeLocation:您在此处使用的,通常是有充分理由的——它们需要时间来完成。鉴于此,您应该首先考虑您的设计并确定您是否真的应该尝试以同步方式使用异步方法。

如果您确实决定需要这样做,那么一种解决方案是使用信号量。在调用reverseGeocodeLocation:创建信号量之前dispatch_semaphore_create(GCD 的一部分,在手册的第 3 节中)。然后在您的块内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 回答