I'm having trouble with CoreLocation region delegate methods in iOS 5, both in simulator and on devices. I'm trying to add a region for monitoring, and then waiting for the didStartMonitoring
delegate callback. Rarely, it works fine. However, usually neither didStartMonitoring
nor monitoringDidFail
get called. The region does get added to monitoredRegions
. The delegate object is set correctly, and usually gets calls for didEnterRegion
and didExitRegion
. The location manager is never released. This is on the main thread. I've checked all the conditions I can think of.
-(id) init
{
self = [super init];
if( self ) {
NSLog( @"initializing location manager" );
self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
return self;
}
-(void) startMonitoringRegion
{
BOOL monitoring = NO;
if ( [CLLocationManager regionMonitoringAvailable] ) {
if ( [CLLocationManager regionMonitoringEnabled] ) {
if( [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized ) {
monitoring = YES;
} else {
NSLog( @"app is not authorized for location monitoring" );
}
} else {
NSLog( @"region monitoring is not enabled" );
}
} else {
NSLog( @"region monitoring is not available" );
}
if( !monitoring ) return;
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:locationManager.location.coordinate
radius:50
identifier:@"majorRegion"];
NSLog( @"trying to start monitoring for region %@", region );
[locationManager startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyBest];
}
-(void) locationManager:(CLLocationManager*)manager
didStartMonitoringForRegion:(CLRegion*)region
{
NSLog( @"region monitoring started" );
}
- (void) locationManager:(CLLocationManager *)manager
monitoringDidFailForRegion:(CLRegion *)region
withError:(NSError *)error
{
NSLog( @"region monitoring failed" );
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog( @"location manager failed" );
}
Anybody have any ideas? I can handle this, but it appears that the didEnterRegion
and didExitRegion
delegate methods are also sometimes inconsistent, and that's a big problem for me.
Edit: I can replicate this functionality within a single app delegate -- no custom objects or anything. See implementation below. The regions get added (seen when printed), but didStartMonitoringRegion
never gets called.
@implementation AppDelegate
@synthesize window = _window;
@synthesize locationManager;
-(void) startMonitoringRegion
{
BOOL monitoring = NO;
if ( [CLLocationManager regionMonitoringAvailable] ) {
if ( [CLLocationManager regionMonitoringEnabled] ) {
if( [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized ) {
monitoring = YES;
} else {
NSLog( @"app is not authorized for location monitoring" );
}
} else {
NSLog( @"region monitoring is not enabled" );
}
} else {
NSLog( @"region monitoring is not available" );
}
if( !monitoring ) return;
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:locationManager.location.coordinate
radius:50.
identifier:@"majorRegion"];
NSLog( @"trying to start monitoring for region %@", region );
[locationManager startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyBest];
}
-(void) printMonitoredRegions
{
NSLog( @"printing regions:" );
for( CLRegion* region in locationManager.monitoredRegions )
NSLog( @"%@", region );
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSLog( @"initializing location manager" );
self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
[self startMonitoringRegion];
[self performSelector:@selector(printMonitoredRegions) withObject:nil afterDelay:2.];
return YES;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
//NSLog( @"location updated" );
}
-(void) locationManager:(CLLocationManager*)manager
didStartMonitoringForRegion:(CLRegion*)region
{
NSLog( @"region monitoring started" );
}
-(void) locationManager:(CLLocationManager*)manager didEnterRegion:(CLRegion*)region
{
NSLog( @"did enter region" );
}
-(void) locationManager:(CLLocationManager*)manager didExitRegion:(CLRegion*)region
{
NSLog( @"did exit region" );
}
- (void) locationManager:(CLLocationManager *)manager
monitoringDidFailForRegion:(CLRegion *)region
withError:(NSError *)error
{
NSLog( @"region monitoring failed" );
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog( @"location manager failed" );
}
@end
Log:
2012-02-21 10:53:50.397 locationtest[64440:f803] initializing location manager
2012-02-21 10:53:50.412 locationtest[64440:f803] trying to start monitoring for region (identifier majorRegion) <LAT,LONG> radius 50.00m
2012-02-21 10:53:52.414 locationtest[64440:f803] printing regions:
2012-02-21 10:53:52.416 locationtest[64440:f803] (identifier majorRegion <LAT,LONG> radius 50.00m
Edit 2: I just noticed that the iOS implementation of the CLLocationManagerDelegate
protocol differs slightly from the Mac implementation -- notably, Mac doesn't have didStartMonitoringRegion
. Could there be any way I'm accidentally using the Mac libraries instead of the iOS libraries?