Musings of a Mobile Developer

Resume Presentations Android iOS

26 Sep 2014
Abstracting iOS 8 new Location Manager

In the new iOS release, CLLocationManager, the class responsible for retrieving location, gets a major overhaul, by introducing specific permission methods. While you can get some details on these changes by looking at the documentation, I wanted to introduce a wrapper class we are using at Guestful for wrapping all the Location-retrieval logic, especially the backward-compatibility code. This solution is based off Michael Babiy’s code, which exposes a method for enabling a Singleton CLLocationManager class. The method exposed here takes this even further, by allowing any number of “observers” on this class.

The Code

We start off by exposing a protocol for our observers to implement, in our GFLocationManager.h file:

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

@protocol GFLocationManagerDelegate

- (void)locationManagerDidUpdateLocation:(CLLocation *)location;


@interface GFLocationManager : NSObject<CLLocationManagerDelegate>

+ (GFLocationManager *)sharedInstance;
- (void) addLocationManagerDelegate:(id<GFLocationManagerDelegate>) delegate;
- (void) removeLocationManagerDelegate:(id<GFLocationManagerDelegate>) delegate;


The interface for our GFLocationManager is pretty straightforward: we provide with a sharedInstance method (singleton, duh!) and two methods to add/remove our observer. Don’t forget to implement the protocol CLLocationManagerDelegate.

On the GFLocationManager.m side, we initiate our manager by following the new iOS 8 requirements, and simply broadcast any new location updates to the observers:

#import "GFLocationManager.h"

@interface GFLocationManager()

@property (strong, nonatomic) CLLocationManager* manager;
@property (strong, nonatomic) NSMutableArray *observers;


@implementation GFLocationManager
static int errorCount = 0;

//This is a singleton the objective-c way
+ (GFLocationManager*) sharedInstance {
    static GFLocationManager *sharedInstance = nil;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        sharedInstance = [[self alloc] init];
    return sharedInstance;

- (instancetype) init {
    self = [super init];
    if(self) {
	//Must check authorizationStatus before initiating a CLLocationManager
        CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
        if (status == kCLAuthorizationStatusRestricted && status == kCLAuthorizationStatusDenied) {
        } else {
            _manager = [[CLLocationManager alloc] init];
            _manager.delegate = self;
            _manager.desiredAccuracy = kCLLocationAccuracyBest;
        if (status == kCLAuthorizationStatusNotDetermined) {
            //Must check if selector exists before messaging it
            if ([_manager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
                [_manager requestWhenInUseAuthorization];
        _observers = [[NSMutableArray alloc] init];
    return self;

- (void) addLocationManagerDelegate:(id<GFLocationManagerDelegate>)delegate {
    if (![self.observers containsObject:delegate]) {
        [self.observers addObject:delegate];
    [self.manager startUpdatingLocation];

- (void) removeLocationManagerDelegate:(id<GFLocationManagerDelegate>)delegate {
    if ([self.observers containsObject:delegate]) {
        [self.observers removeObject:delegate];

#pragma mark - Location Manager Delegate

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
    [self.manager stopUpdatingLocation];
    for(id<GFLocationManagerDelegate> observer in self.observers) {
        if (observer) {
            [observer locationManagerDidUpdateLocation:[locations lastObject]];

-(void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
    errorCount += 1;
    if(errorCount >= MAX_LOCATION_ERROR) {
        [self.manager stopUpdatingLocation];
	errorCount = 0;


Note a few things:

  • The location manager will stop trying to update location if it fails three consecutive times. This is just a heuristic value; I would be interested to know if there are cases where this won’t be enough.
  • We kick off a retrieval of location every time an observer requests it. This works because CLLocationManager takes care of caching the value

How will you use this?

  • In your viewController, start by implementing the GFLocationManagerDelegate protocol:
- (void) locationManagerDidUpdateLocation:(CLLocation *)location {
    self.currentLocation = location;
  • Then, you can add/remove self in the viewWillAppear and viewWillDisappear methods of your viewController:
-(void) viewWillAppear:(BOOL)animated
    [[GFLocationManager sharedInstance] addLocationManagerDelegate:self];

- (void) viewWillDisappear:(BOOL)animated {
    [[GFLocationManager sharedInstance] removeLocationManagerDelegate:self];

Now, everytime the location is retrieved, the locationManagerDidUpdateLocation will be called.


Introduce time-based refreshing of the location: if addLocationManagerDelegate has not been called in 5 min, schedule it again.

PS: I know I am not supposed to tell you what to do, but, you know, you could always follow me on Twitter