block until reverseGeocode has returned

一曲冷凌霜 提交于 2019-12-20 06:47:43

问题


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

回答1:


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.



来源:https://stackoverflow.com/questions/22079079/block-until-reversegeocode-has-returned

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!