I'm trying to test region monitoring, for that I'm getting current location like this:
- (void)startLocationTracking
{
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
// Start location manager
if ([CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized) {
locationManager = [LocationTracker sharedLocationManager];
locationManager.delegate = self;
[locationManager startMonitoringSignificantLocationChanges];
}
}
And tracking first location with region monitoring like this:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:manager.location.coordinate radius:300 identifier:@"first location initializer"];
NSLog(@"0: %@", manager.location);
NSLog(@"1: %@", region);
[manager startMonitoringForRegion:region];
NSLog(@"[locationManager startMonitoringForRegion:%@];", region);
});
}
Then in every exit from current region I'm monitoring the new location like this:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(@"%s, %@", __PRETTY_FUNCTION__, region);
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(@"%s, %@", __PRETTY_FUNCTION__, region);
NSArray *allRegions = manager.monitoredRegions.allObjects;
if (allRegions.count > 0) {
for (CLRegion *reg in allRegions) {
[manager stopMonitoringForRegion:reg];
}
}
CLLocationCoordinate2D cord = CLLocationCoordinate2DMake(manager.location.coordinate.latitude, manager.location.coordinate.longitude);
CLRegion *regionNew = [[CLRegion alloc] initCircularRegionWithCenter:cord radius:300 identifier:@"new region"];
NSLog(@"region: %@", region);
NSLog(@"regionNew: %@", regionNew);
[manager startMonitoringForRegion:regionNew];
}
I'll explain what I expect to happen:
This doesn't happen.
Where I'm wrong?
I tried on simulator with 'Freeway Drive'.
UPDATE:
Tested and work, due to Apple bug in geofencing, app will support only 7.1+, pretty bad but I don't have an another idea.
I think the way you implement the region monitoring might cause some problems.
Here are the reasons:-
Inside the startLocationTracking
method, your locationManager
is a local object that does not extend over the life cycle of that method. It also means that every time you call startLocationTracking
, there will be a new locationManager
object that is allocated with a new block of memory.
To solve this problem: You should use a singleton locationManager
that is a shared locationManager
for the entire life cycle of the Application.
I believe you should not startMonitoringForRegion
inside the delegate method -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:
. The reason is, if you call startLocationTracking
more once, there will be more than one locationManager. Multiple locationManagers could monitor the same region which may cause multiple notifications.
After you call [manager startMonitoringForRegion:region];
, the region will not be monitored immediately. If you do not believe believe me, try the follow code:-
[locationManager startMonitoringForRegion:region];
NSLog(@"%@",locationManager.monitoredRegions);
You will find out that the region that you just monitored will not be inside the locationManager.monitoredRegions
. Since this is handled on the iOS level, so, I think it might need a few minutes for the region to be ready to be monitored.
You should also understand other limitations for Region Monitoring in iOS:-
An app can register up to 20 regions at a time. In order to report region changes in a timely manner, the region monitoring service requires network connectivity.
In iOS 6, regions with a radius between 1 and 400 meters work better on iPhone 4S or later devices. (In iOS 5, regions with a radius between 1 and 150 meters work better on iPhone 4S and later devices.) On these devices, an app can expect to receive the appropriate region entered or region exited notification within 3 to 5 minutes on average, if not sooner.
Note: Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.
I don't know what your app is about, I believe you should redesign the flow of your app. You should try to monitor the region outside of the delegate methods.
For more information about the Singleton LocationManager, you may check out this answer: Background Location Services not working in iOS 7. There is a complete project on GitHub that contains a Singleton LocationManager class that I named as LocationTracker.
You might also want to check out a glitch for Region Monitoring in iOS 7 that I found out a month ago (with a workaround to solve the glitch): Region Monitoring Glitch on iOS 7 - Multiple Notifications at the same time