Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
234 views
in Technique[技术] by (71.8m points)

ios - block until reverseGeocode has returned

I am trying to find a user's location from a coordinate to save into my database.

To find the location name I am using reverseGeocode. However since it is a block method my self.locationName will return (and save as nil) into the database. So I have tried to find a solution to the problem, and tried to put together the following solution using semaphores to try and block until I get a locationName I can save, but the app just hangs when the save button is pressed. Should I even be going about this problem in this way or is there a better way?

 dispatch_semaphore_t semaphore;

 - (void)reverseGeocode:(CLLocation *)location {
     CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks,                    NSError *error) {

     NSLog(@"Finding address");
     if (error) {
     NSLog(@"Error %@", error.description);
     } else {
     CLPlacemark *placemark = [placemarks lastObject];
     self.locationName = [NSString stringWithFormat:@"%@", ABCreateStringWithAddressDictionary(placemark.addressDictionary, NO)];
     dispatch_semaphore_signal(semaphore);         
            }
     }];
     }



-(NSString *)findLocation:(CLLocation *)startingLocation
{
semaphore = dispatch_semaphore_create(0);
[self reverseGeocode:startingLocation];
 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //should maybe timeout
return self.locationName;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are thinking about this all wrong. That is not how asynchronous code works. Do NOT block until the code returns. Just launch the code to start the reverse geocode, and finish up. Now when the reverse geocode finishes, it calls you back and you can do whatever you want with the returned info. That is the whole point of the completion handler: it doesn't run until the reverse geocode has completed.

Just get rid of the semaphores and let things happen asynchronously. Here is a complete example without the secondary method:

CLLocation* loc = userLocation.location;
[geo reverseGeocodeLocation:loc
          completionHandler:^(NSArray *placemarks, NSError *error)
  {
      if (placemarks) {
          CLPlacemark* p = [placemarks objectAtIndex:0];
          NSLog(@"%@", p.addressDictionary); // do something with address
      }
  }];

As you've already been told, if you really want to call this from another method and then do something further, then pass a block to this method and call the block inside the completion handler. That means the block you passed is code that will run when the geocoding has completed, which is exactly what you want - without semaphores and without freezing the app.

Freezing the app is bad form and the WatchDog will kill your app dead if you do it for too long. Just don't do it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...