我有一个看起来像这样的方法:
-(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
问题很明显 - 它在运行块之前返回。如何让它按预期工作,它可以返回块产生的值?
答案 0 :(得分:1)
最初你有reverseGeocodeLocation
的asssign完成块。但它当时没有打电话。它将在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"];
}];
答案 1 :(得分: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);
}];
}
答案 2 :(得分: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。