Return NSString which is set from inside a block

点点圈 提交于 2019-12-06 07:51:35

Intially you have asssign completion block to reverseGeocodeLocation. But It doesn't call at that time. It will call when reverse Geocode process get complete. But city get return immediately. That's why you get like this.

You can solve by assign it to local property. When completion block get executed . So code should be.

[geocoder reverseGeocodeLocation: location completionHandler:
     ^(NSArray *placemarks, NSError *error) {

         //Get address
         CLPlacemark *placemark = [placemarks objectAtIndex:0];

         self.city = [placemark.addressDictionary objectForKey:@"City"];

     }];

Instead of creating block inside getCityFromLocation, make getCityFromLocation as a block (I mean Callback methods).

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

   }];

}

Asynchronous methods, such as reverseGeocodeLocation: you have used here, are normally that for a very good reason - they take time to complete. In that light you should first consider your design and determine whether you really should be trying to use an asynchronous method in a synchronous manner.

If you do decide you need to do this one solution is to use a semaphore. Before the call to reverseGeocodeLocation: create a semaphore with dispatch_semaphore_create (part of GCD, in section 3 of the manual). Then within your block you use dispatch_semaphore_signal to indicate that the string is ready, and outside your block dispatch_semaphore_wait to block until the string is ready.

Your code modified to do this, typed directly into the answer and not executed:

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

But seriously, consider carefully whether this is what you should be doing.

HTH.

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