Region Monitoring only active on boundary cross? - ios

I'm investigating the use of region monitoring for my app. Basically, I want to define a circle area and if the user is outside this circle, then the app won't work.
As I understand it, region monitoring only checks to see if the user crosses the boundary.
If this is the case, can somebody point me in the direction of a tutorial/blogpost which can help me achieve my goal?

Region Monitoring active on both if user comes in the boundary and goes out from boundary
Following methods are useful to check user comes in or goes out from particular defined boundary area :
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"User Enters in Region");
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"User Goes out from Region");
}

calculate the distance from current location to center of circle.
If distance > radius then outside.

You can use regions for monitoring user's in/out activity but normally you could register for Significant Location Change and then check whether user's location is in some limited distance from the point. You can easily calculate distance between two CLLocation points by calling on one sth like this:
[myLoc distanceFromLocation:locationOfCenterOfCircle]
and compare it with radius. Method above returns result in meters. In this case worth reading will be this especially about Significant Location Change.

You can perform a requestStateForRegion:(CLRegion *) on the CLLocationManager.
This way the delegate class' delegate method :
-(void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region will be fired.
In there you can check if you're inside the region or outside.
So basically if you request the state somewhere near the beginning of your app, you can determine whether the user is in or outside your fence.
That'd make something like :
-(void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region{
if (state == CLRegionStateInside){
// Inside geofence
} else {
// Keep state disabled
}

Related

Location manager region monitoring

I am using following apple cllocation manager region monitoring methods:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLCircularRegion *)region
{
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLCircularRegion *)region
{
}
the problem is that these method does not get called when application is in suspended state and not running.Any help would be appreciated. thanks
Try to use significant location change instead of start updating location.Also there is a limit of radius to monitor ,minimum radius should be 100 m

Geofence methods (Region Monitoring) not getting called while updating locations (Enter and Exit in Region)

I have created a sample application for tracking GPS locations based on geofencing. First of all I have created one geofence and added the same to monitoring, using same location placed a circular overlay on MapView.
CLLocationCoordinate2D centerCoordinate1 = CLLocationCoordinate2DMake(23.518192, 72.337122);
CLCircularRegion *region1 =[[CLCircularRegion alloc] initWithCenter:centerCoordinate1 radius:100 identifier:#"Location First"];
NSLog(#"%#",[region1 description]);
region1.notifyOnEntry=YES;
region1.notifyOnExit=YES;
[self.locationManager startMonitoringForRegion:region1];
NSLog(#"Started Monitoring- %#", [region1 description]);
[self.mapview setShowsUserLocation:YES];
[self.mapview setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
// create circle around monitor region and check if worker location is changed
MKCircle *circle1 = [MKCircle circleWithCenterCoordinate:centerCoordinate1 radius:100];
[self.mapview addOverlay:circle1];
Now, I am testing different co-ordinates in simulator by changing the simulator location by Debug->Location->Custom Locations.
If I am change major lat-long then it will call the region enter/exit methods, but if I am checking with near by locations by +/- with 10 or 20 points in latitude and longitude repetatively.
First Image which is inside the GeoFence
Another Image which is outside the GeoFence
Another image is visually outside the GeoFence, but while setting up this latitude and longitude it does not call region exit method.
Below are the region monitoring methods
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region;
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region;
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region;
I am adding 4 to 5 regions to monitor at the same time.
Any help would be highly appreciated.

iOS Geofence, how to handle when inside region when monitoring starts?

I have been unable to work out how to handle a scenario where the phone is already inside a region when startMonitoringForRegion is called? Other questions have suggested calling requestStateForRegion inside didStartMonitoringForRegion this then calls the method didDetermineState: forRegion:. So the code looks something like this:
- (void)viewDidLoad {
//location manager set up etc...
for (Object *object in allObjects){
CLRegion *region = [self geofenceRegion:object];
[locationManager startMonitoringForRegion:region];
}
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
[self.locationManager requestStateForRegion:region];
[self.locationManager performSelector:#selector(requestStateForRegion:) withObject:region afterDelay:5];
}
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
if (state == CLRegionStateInside){
[self locationManager:locationManager didEnterRegion:region];
}
}
Now obviously the method geofenceRegion is my own and it works fine, and the objects contains things like lat long and radius and that all works fine as well so that is not the problem here.
Anyway, the problem with the above code is that it does work if the user is already inside the region when it adds the region to their device (ie. didEnterRegion is done). However the problem is that the method didDetermineState: forRegion: is also called every time one of the boundary regions is crossed as per the apple docs:
The location manager calls this method whenever there is a boundary transition for a region. It calls this method in addition to calling the locationManager:didEnterRegion: and locationManager:didExitRegion: methods. The location manager also calls this method in response to a call to its requestStateForRegion: method, which runs asynchronously.
Now because of this every time a region is entered, didEnterRegion is automatically called but then it is called again because didDetermineState: forRegion: is also automatically called as per the apple docs and this results in didEnterRegion being called again so the region is entered twice when i only want it to be entered once. How can i avoid this?
Thanks for your help.
SOLUTION
The solution really is so simple i was just going about it the wrong way. I had to choose to either use the 2 methods didEnterRegion: and didExitRegion or use didDetermineState: forRegion and create my own methods for entering and exiting the region, both should not be used.
So i have chosen to use only the didDetermineState: forRegion method and my code now looks like this:
Please note that with this method exit region will be called for the region if not inside and if, like me, you only want exit to happen after an enter has happened you will need some sort of method of checking if the region has already been entered (I myself used core data as i was already using this to store other aspects of the regions).
- (void)viewDidLoad {
//location manager set up etc...
for (Object *object in allObjects){
CLRegion *region = [self geofenceRegion:object];
[locationManager startMonitoringForRegion:region];
}
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
[self.locationManager performSelector:#selector(requestStateForRegion:) withObject:region afterDelay:5];
}
- (void)locationManager:(CLLocationManager *)manager
didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
if (state == CLRegionStateInside){
[self enterGeofence:region];
} else if (state == CLRegionStateOutside){
[self exitGeofence:region];
} else if (state == CLRegionStateUnknown){
NSLog(#"Unknown state for geofence: %#", region);
return;
}
}
- (void)enterGeofence:(CLRegion *)geofence {
//whatever is required when entered
}
- (void)exitGeofence:(CLRegion *)geofence {
//whatever is required when exit
}
Just do not use locationManager:didEnterRegion: at all, as locationManager:didDetermineState:forRegion: gives you all the info you need to trigger the on-entry code, which, by the way, should not be the locationManager:didEnterRegion:, use your own selector, which is not a part of CLLocationManagerDelegate protocol.
Another approach is to test for inside a region location when starting to monitor a region. This solution is not that trivial as it sounds though: you need to update current location first by calling startUpdatingLocation, as just reading location property of locationManager will probably give you stale or extremely inaccurate reading.

iOS remove overlay only when I through the region

I created many overlays in mapView with this code:
MKCircle *circle = [MKCircle circleWithCenterCoordinate:userLocation.coordinate radius:1000];
[mapView addOverlay:circle];
I would like to remove one by one only when I execute methode:
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
My problem is: when I'm coming out of a region, do not know what I went through overlay.
Any idea how I can remove those?
Thank you.
You are going to want to monitor the regions corresponding to your circles.
Create your CLRegion:
- (id)initCircularRegionWithCenter:(CLLocationCoordinate2D)center radius:(CLLocationDistance)radius identifier:(NSString *)identifier
Monitor with CLLocationManager:
- (void)startMonitoringForRegion:(CLRegion *)region
Which will send events to your listener, so you can add/remove the overlays when you receive the events:
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
Probably the easiest way for you will be to store the relationship between MKCircle objects and the corresponding CLRegion objects, so you can update your map appropriately.

Does startMonitoringForRegion actually work?

I've been trying to use startMonitoringForRegion for while, but experiencing problems to capture enter/exit events. When I launch the app on simulator and moved to the location I specified, I get 1 enter event, but enter events never triggered again. Can somebody let me know if I'm doing correctly?
test.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface EWViewController : UIViewController<CLLocationManagerDelegate>
{
CLLocationManager *locman;
}
#end
test.m
- (void)viewDidLoad
{
if(locman == nil)
locman = [[CLLocationManager alloc]init];
locman.delegate = self;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(37.787359, -122.408227);
CLRegion *region = [[CLRegion alloc]initCircularRegionWithCenter:coord radius:1000.0 identifier:#"SF"];
[locman startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyKilometer];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void) locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(#"ENTER");
}
- (void) locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"EXIT");
}
I have been using region monitoring for a geofence feature in my app for about 6 months and I have found it to be very precise. Once you have everything wired up correctly, it can be used to track enter and exit events quite well.
While you can get even better and more precise readings from -didUpdateToLocation, you will have to trade off battery life to get it. If you only need occasional location updates, it should be fine. If you need constant monitoring for specific locations, region monitoring is the way to go.
I have found that -startMonitoringForSignificantLocation is not accurate at all and not very practical. It relies solely on cell tower transitions and triangulation. It also can't be used to test in the simulator for this very reason. Hope some of this information helps you out.
Yes it works, but it is very very unprecised for the current moment. (I tested it in Russia)
I recommend you using this instead:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;

Resources