After updating to iOS 8, when using the CLLocationManager to monitor for regions, my delegate was not getting any callbacks.

The problem

The error I was presented with, when trying to run my iOS 7 compatible code on iOS 8 was:

Error Domain=kCLErrorDomain Code=4 "The operation couldn’t be completed. (kCLErrorDomain error 4.)"

CLError shows the error code is kCLErrorRegionMonitoringDenied. With the enhanced focus on user privacy in iOS 8, I figured it had to be caused by updates to user permissions.

The solution

Apple docs state that a request to the CLLocationManager along with a usage description is now required. There are two permission options for dealing with location services: whenInUseAuthorization and alwaysAuthorization. The names are pretty self-explanatory, so choose the option that fits the requirements of your app. Apple docs also does a pretty good job at describing the difference, if needed.

Add usage description

First, you need to add a usage description to the application .plist

The keys are NSLocationWhenInUseUsageDescription and/or NSLocationAlwaysUsageDescription.


Authorize through CLLocationManager

Right before using the CLLocationManager, call the new requestAlwaysAuthorization or requestWhenInUseAuthorization again, depending on your app's requirements.

This will prompt the user with the new usage description.

CLLocationManager *locationManager = [CLLocationManager new];

if ([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
    [locationManager requestAlwaysAuthorization]; //or requestWhenInUseAuthorization

It's still important to consider when the appropriate time to prompt the user is. Usually you should wait until the CLLocationManager is about to be used in the app instead of doing it at app launch.