One interesting feature in the new version of Watch Over Me app is Crime Zone. The main purpose of the crime zones is to notify the user of Watch Over me when he/she is passing the area. Watch Over Me app will ask if the user wants to be watched over during that time.
We have accumulated some trustable and reliable resources from various websites from the Internet to gather the crime zone areas in 7 major cities in 5 different countries (Malaysia, USA, UK, Australia, Thailand). These 7 cities are our test regions and we will be adding more regions in the future.
iOS Region Monitoring and Location Manager
I am using Region Monitoring from the Location Manager to implement this feature on the iOS Watch Over Me app. This particular module is not hard compare with getting the location in iOS 7 in background mode.
The maximum regions that an iOS device can monitor is only limited to 20. So, I have to come out with a good strategy to only get and monitor the regions that are useful to the users.
This is the logic we use for the region monitoring in iOS:-
1. Getting the current location from the user.
2. Send the current location to the server.
3. The server will return all the regions within a 20 km radius from the current location
4. If there are more than 20 regions, the server will only send the closest 20 regions from the current location.
5. After receiving the regions, the app will start to monitor the regions.
A Potential Bug for locationManager delegate method didEnterRegion
After the app has been released on the app store, we are still constantly in testing on the region monitoring on Kuala Lumpur (KL). We have 8 monitored regions in KL at the time of typing this article.
On one fine day, my colleague saw a bug with multiple region notifications triggered at the same time. The location of my colleague is at least 3000 meters away from the nearest region that we monitored. I have double checked on the radius and also the coordinate for all the regions that we monitor in KL, there wasn’t any discrepancy of the data.


The screen on the Left shows the bug when 4 notifications triggered at the same time when the device is NOT even close to any of the regions.
The screen on the Right is a simple app that I made to stimulate the location of the device (Green Marker) and also the location (Red Marker) and the radius of each region (Red Circle). The Blue Circle is the estimation of the radius of the device when it triggered the notification for all 4 regions. The estimated radius for the device is about 4700 meters! It should not happen.
I have searched through various websites (StackOverFlow, Apple Developer Forum and etc.), I couldn’t find other developer faced the same issue like mine. I saw a lot of questions on NOT getting any notification when passing through a region, but my case is the entire opposite.
I am not sure if this is the fault on my code, on iOS system level or the problem on the local Telco in my country. I have posted a question on StackOverFlow for more than 1 week but I didn’t get any answer as well.
How to Fix this Bug?
Without much reliable information, I can only do trial and error in order to fix this bug. I have been trying a few different method on trying to fix the bug. This includes setting the distanceFilter = 10 for the locationManager. Previously, it was kCLDistanceFilterNone because I want the app to detect every single movement.
//locationManager.distanceFilter = kCLDistanceFilterNone; locationManager.distanceFilter = 10;
My colleague still saw this bug after a few days of testing. So, the above solution is no good.
After experimenting for sometimes, I found a solution that works good.
1. Whenever a user enters a monitored region, he/she will get a notification in the locationManager delegate method didEnterRegion. But due to the bug, this method is not reliable. I have to use a smart way to filter out the fake location.
2. I found a way to get the recent location of the user from locationManager.
3. After the app gets the user location, the app will make sure that the location is within the region before deciding to send the location notification to the device.
From my research, this location is not 100% reliable, especially if there isn’t any location based running at the background. But generally, it is good enough to filter out the bad location which may trigger multiple notifications for different regions.
Here are the example code:
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{ CLLocation * lastLocation = [manager location]; BOOL doesItContainMyPoint; if(lastLocation==nil) doesItContainMyPoint = NO; else{ CLLocationCoordinate2D theLocationCoordinate = lastLocation.coordinate; CLCircularRegion * theRegion = (CLCircularRegion*)region; doesItContainMyPoint = [theRegion containsCoordinate:theLocationCoordinate]; } if(doesItContainMyPoint){ NSString* message = [NSString stringWithFormat:@"You are now in this region:%@",region.identifier]; UIApplicationState state = [[UIApplication sharedApplication] applicationState]; if (state == UIApplicationStateBackground || state == UIApplicationStateInactive) { UILocalNotification *notification = [[UILocalNotification alloc] init]; notification.fireDate = [NSDate date]; NSTimeZone* timezone = [NSTimeZone defaultTimeZone]; notification.timeZone = timezone; notification.alertBody = message; notification.alertAction = @"Show"; notification.soundName = UILocalNotificationDefaultSoundName; [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } } }
Hello,
I am facing the same problem. I start monitoring the regions and the method didEnterRegion is triggered even if i am really far. I didnt test your solution yet, but i think that way if the region does not contain the user location, the didEnterRegion will not be called again until the didExitRegion is called. I will test your solution and provide a new feedback.
I’m sorry for my english and thank you for sharing.
Tiago Pereira
Hi,
This solution is not working for me.
Hello,
my thought is same as TIAGO PEREIRA’s.
So I’d like to know the real cause of the problem.
As far as I search about geofencing, it seems possible to get accurate notifications like 100 meters.
If you’ve already found out the reason, please tell me, please.
Thanks in advance.
Thanks for writing about this – i’m having the same problem and couldn’t find anyone other than you talking about it. containsCoordinate isn’t really how I want to deal with this, but it will have to do for now.
If you’ve any updates on this, since the original post, i’d love to hear about it.
Just wondering. Did you file a bug report to Apple? It seems weird, as it’s a pretty serious bug they don’t seeem to address.
I’m seeing this same behavior in iOS 8.4. I have a large(ish) user base that will send webhooks to my server based on didEnter and didExit region monitoring. In my webhooks I’m sending the details of the geofence that the user triggered and the user’s location. With that data, I’m finding a large number of users (~80%) sending me webhooks are really far away – several kilometers – from the geofence! Here’s the rub, the horizontal accuracies from the user’s location are actually pretty good, some as low as 10m. I can recreate this behavior when I turn WiFi off. My experience has led me to believe that perhaps region monitoring isn’t interacting correctly with location data from the GPS. I’ve adopted your solution and see that manually forcing the comparison of region area against the manager’s location. Does anyone notice this behavior when WiFi is on? Is it possible that region monitoring isn’t getting data from the GPS (that seems crazy)?
**HERE is fullproof working solution/fix for iOS geo-fencing glitch !
Solution modified after referring to below mentioned post**
region monitoring for iOS
Basically, distanceFilter = kCLDistance FilterNone and desiredAccuracy = kCLLocatio nAccuracyBestFor Navigation
– (void) locationManager: (CLLocationManager *) manager didEnterRegion:(CLRegion *)region
{
CLLocation * lastLocation = [manager location];
BOOL doesItContainMyPoint;
if(lastLocation ==nil)
doesItContainMyPoint = NO;
else{
CLLocation Coordinate2D theLocation Coordinate = lastLocation.coordinate;
CLCircular Region * theRegion = (CLCircularRegion*) region;
//we need to take new instance of given region for which the iOS triggers entry event..Adding 50.0 meters is needed just to make sure that contains Coordinate method of CLCircularRegion works well.Because there is lag/difference measured in our real time field testing that brought us to this conclusion and it works like a charm.
CLCircularRegion * theCircularRegion = [[CLCircularRegion alloc] initWithCenter:theRegion.center radius: theRegion. radius+50.0 identifier:theRegion.identifier];
doesItContainMyPoint = [theCircularRegion containsCoordinate: theLocationCoordinate];
}
if(doesItContainMyPoint){
NSLog(@”ItContainMyPoint”);
//trigger local notification…
}else{
NSLog (@”ItDoesNot ContainMyPoint”);
//do not trigger local notification…because it is triggered due to switching network(wifi to mobile data and vice versa) Currently user is not at all in the region for which we are getting event of entry
return;
}
}
Actually still i did not attender stand how it will going to helpfull.
I want give 30 meters region.and my enterRegion method is triggering at when i am before 70 meters(approcs).and this method is going to be call at only once.so how can check the user is inside the region and how again the enterRegion method will call at right region
-(void)location Manager: (CLLocation Manager *)manager did EnterRegion:(CLRegion *)region{
CLLocation * lastLocation = [manager location];
BOOL doesItContainMyPoint;
if(lastLocation==nil)
doesIt ContainMyPoint = NO;
else{
CLLocation Coordinate2D theLocation Coordinate = lastLocation .coordinate;
CLCircularRegion * theRegion = (CLCircularRegion*) region;
doesItContainMyPoint = [theRegion contains Coordinate: theLocationCoordinate];
}
if(doesItContain MyPoint){
NSString* message = [NSString stringWithFormat:@”You are now in this region:%@”,region.identifier];
UIApplicatio nState state = [[UIApplication shared Application] applicationState];
if (state == UIApplication StateBackground || state == UIApplication StateInactive)
{
UILocal Notification *notification = [[UILocal Notification alloc] init];
notification.fireDate = [NSDate date];
NSTimeZone* timezone = [NSTimeZone default TimeZone];
notification .timeZone = timezone;
notification .alertBody = message;
notification .alertAction = @”Show”;
notification .soundName = UILocal NotificationDefault SoundName;
[[UIApplication sharedApplication] scheduleLocal Notification :notification];
}
}
}
How can i use this in my situation.