Looks like you found a workable solution and it seems like using the significant change framework would save you some battery life, so long as it is accurate enough for your purposes. Your solution is also beneficial because it allows you to juggle potentially more than the per-app limit of 20 regions allowed to be simultaneously monitored, by only monitoring those regions that you are closest to.
I need similar functionality, but don't think the significant change would be accurate enough for my app, so I dug around some more and found the following.
Per the Location Awareness Programming Guide, under "Monitoring Shape-Based Regions":
In iOS, regions associated with your app are tracked at all times, including when your app is not running. If a region boundary is crossed while an app is not running, that app is relaunched into the background to handle the event. Similarly, if the app is suspended when the event occurs, it is woken up and given a short amount of time to handle the event.
And also in "Handling Boundary-Crossing Events for a Region":
Every time the user’s current location crosses a boundary region, the system generates an appropriate region event for your app. If your app is already running, these events go directly to the delegates of any current location manager objects. If your app is not running, the system launches it in the background so that it can respond. Apps can implement the following methods to handle boundary crossings:
locationManager:didEnterRegion:
locationManager:didExitRegion:
In my case, I just needed to fire a notification when the boundary was crossed, so I set my AppDelegate to conform to CLLocationManagerDelegate, created a locationManager property, and put this in my implementation file:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.locationManager.delegate = self;
return YES;
}
- (CLLocationManager *)locationManager
{
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
}
return _locationManager;
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"You crossed a boundary!", @"user crossed a boundary");
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}
Testing shows this works without the UIBackgroundModes location key needing to be set. In this use-case, the OS handles boundary monitoring for you and then sends the event to your app just long enough to process the event. This doesn't launch the app, it just runs it in the background for a few seconds to process the boundary event, during which time you can only do relevant activities. Hope this helps someone else, too!