CLGeocoder as an External Function Call

By | December 12, 2013
geocoding

If you don’t know what CLGeocoder does or what Geocoding is, take  a look at this tutorial that I wrote a few years ago as it is a good starting point.

A standard call to CLGeocoder looks a bit like this:

[self.geoCoder reverseGeocodeLocation:toGeocode completionHandler:^(NSArray *placemarks, NSError *error) {
            
            CLPlacemark *placemark = [placemarks objectAtIndex:0];
            NSLog(@"%@",[[placemark.addressDictionary valueForKey:@"FormattedAddressLines"] componentsJoinedByString:@", "]);
            
        }];

This basically takes a given location as a CLLocation and take its Latitude and Longitude properties, it will then generate a textual address for the corresponding real world place for those coordinates. This is known as Reverse Geocoding.

This is a very simple implementation and can be easily integrated into any xCode project. However you may find that if you need to make multiple calls to a CLGeocoder you might want to move the Geocoder into a function all by itself so that you can just call [myLocationManager nameOfPlaceFor:myLocationObject]; and in this example that may return a String.

When you actually implement this function however you will probably run into some problems, you can’t access the Formatted Address Dictionary before the Geocoder has finished and called its completion block. The problem here is that if for example you have a function that returns a String like our example above, you may end up returning a nil String before your CLGeocoder has finished. This happens because the CLGeocoder block is handling Asynchronous Networking , we won’t know that it has finished until the Completion block has been called.

So the solution then is to use another block :)

Lets create a function in our Singleton/Manager/Insert Your External Class Here

Firstly place this Function Prototype in your Singleton/Manager/ header file (.h)

- (void)reverseGeocodedAddressFor:(CLLocation *)toGeocode :(void(^)(NSString *reverseGeocodedString))completionBlock;

Then in your Singleton/Manager (.m) implement this method.

- (void)reverseGeocodedAddressFor:(CLLocation *)toGeocode :(void (^)(NSString *))completionBlock{
        
        [self.geoCoder reverseGeocodeLocation:toGeocode completionHandler:^(NSArray *placemarks, NSError *error) {
            
            CLPlacemark *placemark = [placemarks objectAtIndex:0];
            completionBlock([[placemark.addressDictionary valueForKey:@"FormattedAddressLines"] componentsJoinedByString:@", "]);
            
        }];
    
    
    
}

Then finally in the class that you wish to access your Singleton/Manager from , in the .m file implement the function that we just created.

[self.ugLocationManager reverseGeocodedAddressFor:location :^(NSString *reverseGeocodedString) {
       NSLog("Location Retrieved as %@",reverseGeocodedString);
    }];

Now when the CLGeocoder finishes, its competition block will call the Completion Block that we created as part of our Singleton/Manager method. This is really helpful when doing things like Showing the Address of a location when a Pin is dropped on the Map. Hopefully this should not return nil under normal circumstances and you can now access it multiple times from many different classes rather than having to implement individual CLGeocoder blocks every time.

Leave a Reply