我是新来的Objective-C和我的C / C ++的技能是非常生疏。 有什么更好的时间来学习iOS开发(!)
我试图扭转大地定位用在iOS中CLGeocoder类的位置。 我能顺利拿到我感兴趣的(街道地址)块/回调里面的数据,但是当我尝试使用这些数据来填充我变量(块之外)的数据是不存在的。 这是因为如果的MapView对象调用它之前的块中的对象消失。 我使用__block其按我的理解,应该允许变量外块依然存在,但它似乎没有。
这里是有问题的代码:
- (void) foundLocation:(CLLocation *)loc
{
CLLocationCoordinate2D coord = [loc coordinate];
// Get our city and state from a reversegeocode lookup and put them in the subtitle field (nowString).
// reversegeocode puts that information in a CLPlacemark object
// First, create the CLGeocoder object that will get us the info
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
// Next create a CLPlacemark object that we can store what reverseGeocodeLocation will give us containing the location data
__block CLPlacemark *placemark = [[CLPlacemark alloc]init];
__block NSString *sPlacemark = [[NSString alloc]init];
// This next bit is where things go awry
[geocoder reverseGeocodeLocation:loc completionHandler:
^(NSArray *placemarks, NSError *error) {
if ([placemarks count] > 0)
{
placemark = [placemarks objectAtIndex:0];// this works!!
sPlacemark = [placemark thoroughfare]; // as does this! I can see the street address in the variable in the debugger.
}
}];
MapPoint *mp = [[MapPoint alloc] initWithCoordinate:coord
title:[locationTitleField text]
subtitle:sPlacemark];
// add it to the map view
[worldView addAnnotation:mp];
// MKMapView retains its annotations, we can release
[mp release];
// zoom region to this location
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 250, 250);
[worldView setRegion:region
animated:YES];
[locationTitleField setText:@""];
[activityIndicator stopAnimating];
[locationTitleField setHidden:NO];
[locationManager stopUpdatingLocation];
}
我还没有完全包裹我的头周围的“块”,所以很可能这就是问题的所在,但我不能把我的手指上到底是什么。
所以,你所拥有的是一个时机的问题。 要将呼叫reverseGeocodeLocation:completionHandler:
是异步的 。 实际的反向地理定位发生之前调用本身将立即返回。
于是立即为调用返回时,你的方法继续,并且您要创建与尚不存在一个标注释。
然后在某一点后 ,你的反向地理定位完成(还记得它需要一个网络呼叫服务和所有的)。 然后,在这之后,你的块与新传入的数据被解雇。
因此,通过你的模块实际上运行的时间,创建这两个地方__block变量早已不复存在。 为什么? 因为这些变量placemark
和sPlacemark
是本地的(自动)变量,局部于该方法。 他们来到这个方法中存在,然后走开时结束该方法。 再次,这种情况发生在你的块甚至已经开始运行。 (原来的块将写入每个变量后的副本,但其实并不重要,因为这种方法是通过接完,你已经尝试过过早阅读。)
如果你把一个NSLog的消息,在这种方法中,而另一个在块的末尾,你会看到他们解雇序列。 此次订货会是怎样的你可能在想相反。 在该方法结束时,应该先触发,然后将块内的一个。
想到这就像一个餐厅。 服务员又回到了厨房和下订单。 现在他不会在厨房坐在那里等待被煮的菜,因为这需要时间。 于是,他离开的命令,并继续他的工作,直到时间的顺序是准备好了。 现在想象他离开的命令,然后立即检查柜台。 他会很失望地看到,食品现在还没有。 而这正是你在做什么,当你马上尝试读取placemark
变量的厨师已经收到哪怕一秒钟做饭的顺序。
所以,答案是什么? 你可以创建一个用于创建注释,并把它在地图上的另一种方法。 这种方法应采取标作为参数,然后你可以调用从块内的方法(这又是你确实有地标后)。这个作为所有服务员想后做的顺序是工作准备好了,就像拿订单给用户。
还有其他的方法来做到这一点。 但是,对于一个单一标的为您展示在这里,这是一个简单的方法来处理这个问题。 很明显,你还应该添加错误处理的情况下,你无法找到地标,或者服务不可用,等等。如果查找失败,标会是零,您可以检查错误的详细信息。
希望帮助。
Firoze我遇到了同样的问题。 我最后写的是拍了“完成”块作为PARAM这样,当地理编码结束我将有机会获得它在特定块的自定义方法。
- 片段
- (void)fetchForwardGeocodeAddress:(NSString *)address withCompletionHanlder:(ForwardGeoCompletionBlock)completion {
if (NSClassFromString(@"CLGeocoder")) {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLGeocodeCompletionHandler completionHandler = ^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(@"error finding placemarks: %@", [error localizedDescription]);
}
if (placemarks) {
[placemarks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
CLPlacemark *placemark = (CLPlacemark *)obj;
NSLog(@"PLACEMARK: %@", placemark);
if ([placemark.country isEqualToString:@"United States"]) {
NSLog(@"********found coords for zip: %f %f", placemark.location.coordinate.latitude,placemark.location.coordinate.longitude);
if (completion) {
completion(placemark.location.coordinate);
}
*stop = YES;
}
}];
}
};
[geocoder geocodeAddressString:address completionHandler:completionHandler];
} else {
/**
* Since the request to grab the geocoded address is using NSString's initWithContentsOfURL
* we are going to make use of GCD and grab that async. I didn't put this in the
* method itself because there could be an instance where you would want to make a
* synchronous call. Better to have flexibility.
*
* Possible improvement could be to write another method that does the async
* loading for you. However, if you did it that way how would you be notified
* when the results returned. Possibly KVO?
*/
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
CLLocation *location = [address newGeocodeAddress];
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(location.coordinate);
}
});
});
}
}
在我的具体使用情况下,我不得不支持iOS4的和iOS5的,因此检查和额外的逻辑。 我给我的关于它的博客更多的细节: http://blog.corywiles.com/forward-geocoding-in-ios4-and-ios5