startMonitoringForRegion never calls didEnterRegion/didExitRegion

oliverk picture oliverk · Nov 11, 2010 · Viewed 9.4k times · Source

I try to get the iPhone4 to monitor regions and notify me by call didEnterRegion or didExitRegion. I can't get it to work. I was reading probably all related enries here, plus a couple more articles on the web....iOS just don't call my CLLocationManagerDelegate methods. What did I do:

I have a simple AppDelegate which implements also the CLLocationManagerDelegate methods for didEnterRegion and didExitRegion. Within these methods I simply use a UILocalNotification to report the event. From a ViewController I create a Region (the current Location) with aRadius of 1000meters.

Answer

cduhn picture cduhn · Dec 6, 2011

Here are some things to check:

  1. Before you start monitoring regions in your code, call [CLLocationManager regionMonitoringAvailable] and [CLLocationManager regionMonitoringEnabled] to make sure the service is available and enabled on the user's phone.

  2. Make sure you have the location manager's delegate property set to the object where you've implemented locationManager:didEnterRegion: and/or locationManager:didExitRegion:.

  3. Make sure you don't have any typos in those method signatures. A small capitalization error would cause delivery of these messages to fail. Copy/paste these into your code and make sure they match:

    - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
    { /* Handle enter */ }
    
    - (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
    { /* Handle exit */ }
    
  4. Make sure your delegate also implements locationManager:monitoringDidFailForRegion:withError:, as it may tell you why the service is failing.

    - (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
    {
        NSLog(@"Region monitoring failed with error: %@", [error localizedDescription]);
    }
    
  5. One reason a monitoring failure like this may occur is that Core Location imposes a limit on the number of regions an app is allowed to monitor. In practice this limit seems to be about ten regions per app. So make sure you remove regions you don't need using stopMonitoringForRegion:, and monitor only those regions nearest the user as recommended by Apple's Location Awareness Programming Guide:

    You should always be judicious when specifying the set of regions to monitor. Regions are a shared system resource and the total number of regions available systemwide is limited. For this reason, Core Location limits the number of regions that may be simultaneously monitored by a single application. To work around these limits, you should consider registering only those regions in the user’s immediate vicinity. As the user’s location changes, you can remove regions that are now farther way and add regions coming up on the user’s path. If you attempt to register a region and space is unavailable, the location manager calls the locationManager:monitoringDidFailForRegion:withError: method of its delegate with the kCLErrorRegionMonitoringFailure error code.

  6. Hopefully obvious, but make sure you're calling startMonitoringForRegion:desiredAccuracy: after setting your delegate.

  7. When you initialize the CLRegion object that you're monitoring using initCircularRegionWithCenter:radius:identifier:, make sure you use a unique identifier for each region.

  8. If your locationManager:didEnterRegion: and locationManager:didExitRegion: methods are getting called properly when the app is active, but not when the OS relaunches your app in the background after it's been killed, then you may not be properly initializing your location manager and setting its delegate in that case. If you cross a registered region boundary when the app isn't running, the OS will launch your app in the background, which you can detect using if ([launchOptions objectForKey:@"UIApplicationLaunchOptionsLocationKey"]]) {} in the application:didFinishLaunchingWithOptions: method of your app delegate. Your app probably won't load any views when it's launched in the background like this, so you need to make sure application:didFinishLaunchingWithOptions: invokes some code path that instantiates your location manager object and sets its delegate in this case. As soon as your location manager's delegate property gets set, any pending region monitoring events will be delivered.