Im relatively a new iOS developer, and im dealing with the geocoder completion handler, i do not understand how to update a variable with the address find by the geocoder and the do some stuff with it. In few words, i want that the geocoder block finishes to use the info in some method.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(@"didUpdateToLocation: %@", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
longitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
latitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
}
[locationManager stopUpdatingLocation];
// Reverse Geocoding
NSLog(@"Resolving the Address");
__block NSString * **annotation**;
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
NSLog(@"location %@",addressLabel);*/
**annotation**=[NSString stringWithFormat:@" %@, %@, %@",
placemark.locality,
placemark.administrativeArea,
placemark.country];
}
} ];
NSLog(@"location %@",annotation);
NSString *text = self.toPostCell.postText.text;
UIImage *image = self.toPostCell.selectedImage.image;
[Persistence addPostToServerAddtext:text addimage:image addbeach:nil **location:annotation**];
[NSThread sleepForTimeInterval:5.0];
self.posts = [Persistence getPostsUpTo: self.cantPosts forBeach:nil];
imageLoaded = NO;
[self.tableView reloadData];
}
I have tried the dispatch main queue, and i cant get the annotation and use it in the method, after a deep search around the web im a bit confused about threads, queues and the order of there execution. When running the method it throws the exception EXC_BAD_ACCESS when logging the annotation after the block....
The reverseGeocodeLocation
method runs asynchronously, so you shouldn't reference the annotation
outside of the completionHandler
block. The annotation
string has not been set by the point you get to that code after the reverseGeocodeLocation
block.
Thus, you might want to move your code after the reverseGeocodeLocation
block to inside it, resolving this asynchronous issue:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(@"didUpdateToLocation: %@", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
longitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
latitudeLabel = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
}
[locationManager stopUpdatingLocation];
// Reverse Geocoding
NSLog(@"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
NSLog(@"location %@",addressLabel);*/
NSString *annotation = [NSString stringWithFormat:@" %@, %@, %@",
placemark.locality,
placemark.administrativeArea,
placemark.country];
NSLog(@"location %@",annotation);
NSString *text = self.toPostCell.postText.text;
UIImage *image = self.toPostCell.selectedImage.image;
[Persistence addPostToServerAddtext:text addimage:image addbeach:nil location:annotation];
// I'm not sure why you're sleeping 5 seconds, but if you really want to do
// something five seconds later you should probably `dispatch_after`, thus
// instead of:
//
// [NSThread sleepForTimeInterval:5.0];
//
// you might want to do the following:
double delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
self.posts = [Persistence getPostsUpTo: self.cantPosts forBeach:nil];
imageLoaded = NO;
[self.tableView reloadData];
});
}
} ];
}
Basically without running your app, you are trying to log your location, but there is not guarantee that the block has ran before you invoke "NSLog"
If you wish the log not to crash do it this way, inside the same block;
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(@"Found placemarks: %@, error: %@", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
NSLog(@"location %@",addressLabel);*/
**annotation**=[NSString stringWithFormat:@" %@, %@, %@",
placemark.locality,
placemark.administrativeArea,
placemark.country];
NSLog(@"location %@",annotation);
}
} ];
This way you can assure "annotation" was set before logging, and avoid the EXC_BAD_ADDRESS resulting from referring to a null pointer...