返回从块内部设置的NSString

我有一个看起来像这样的方法:

-(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 

问题很明显 – 在块运行之前就会返回。 我怎么能得到这个按预期工作,在哪里可以返回块产生的价值?

内在你有asssign完成块来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"]; }]; 

getCityFromLocation代替在getCityFromLocation中创build块,使getCityFromLocation成为块(我的意思是callback方法)。

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

asynchronous方法,如reverseGeocodeLocation:在这里使用,通常是出于一个很好的理由 – 他们需要时间来完成。 有鉴于此,您应该首先考虑您的devise,并确定您是否应该尝试以同步方式使用asynchronous方法。

如果你确实需要做这个解决scheme就是使用信号量。 在调用reverseGeocodeLocation:之前reverseGeocodeLocation:使用dispatch_semaphore_create (手册的第3部分中的GCD的一部分)创build一个信号量。 然后在您的块内使用dispatch_semaphore_signal指示string已准备就绪,并在dispatch_semaphore_wait块之外进行阻塞,直到string准备就绪。

您的代码被修改为执行此操作, 直接键入到答案,而不是执行

 #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。