13

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:

  1. Register current location in region monitoring.
  2. Notify user exit current region.
  3. On exit log and register again the current location as region.

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.

Ricky
  • 10,485
  • 6
  • 36
  • 49
Idan Moshe
  • 1,675
  • 4
  • 28
  • 65
  • 1
    Well, you should never test this kind of behaviour on a simulator. You will need a real device for this. I tried doing this once for a location tracker app but it just bugged out randomly on a simulator. – Totumus Maximus Jun 16 '14 at 14:40
  • Tested in real time, still doesn't work. – Idan Moshe Jun 16 '14 at 17:25
  • Can you elaborate on your update? Does your code in your question now works without the solution provided in the answer? – rene Jun 24 '14 at 19:19
  • I know it has been long time to this question, but in Geofencing I am facing problem. I have selected 100 meters radius and 'upon exit' notification should come. But I am getting notification on/around 250 meters. Please help me out. – Umang Kothari Feb 19 '16 at 09:26

2 Answers2

11

I think the way you implement the region monitoring might cause some problems.

Here are the reasons:-

  1. 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 locationManagerobject 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.

  2. 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.

  3. 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:-

https://developer.apple.com/library/mac/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html

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

Community
  • 1
  • 1
Ricky
  • 10,485
  • 6
  • 36
  • 49
  • 1
    I know it has been long time to this question, but in Geofencing I am facing problem. I have selected 100 meters radius and 'upon exit' notification should come. But I am getting notification on/around 250 meters. Please help me out. – Umang Kothari Feb 19 '16 at 09:27
  • if i want to monitor only one buiding region means how can i set it.If i get the cordinates from google map will work? – Lydia May 05 '16 at 06:16
  • upvoted! While I agree that the RegionMonitoring, SLC, Visit monitoring are all managed on OS level. I *think* it's no longer as you said. From iOS 10, iPhone6, when I do `[locationManager startMonitoringForRegion:region]; NSLog(@"%@",locationManager.monitoredRegions);` I **do** see it immediately. – mfaani Jul 28 '17 at 14:41
  • @UmangKothari I am facing the same issue? Did you find any solution? – Amanpreet May 16 '18 at 06:28
-1

The most satisfactory answer to the delegates methods (didEnterRegion and didExitRegion) not being called is, apple docs says you will be notified after 3 to 5 minutes after the entry or exit, but in actual testing what I found is you have to wait for approx 7 to 8 minutes.

I tested it for 10 to 15 times and my region radius was around 80 meters. I was scratching my head to see what went wrong. I left the simulator open with the location tracking on (Used a gpx file for location simulation). After 8 minutes didExitRegion was called.

Also if you want to do this in background, you must enable background modes on your target. enter image description here

nr5
  • 4,228
  • 8
  • 42
  • 82
  • I know it has been long time to this question, but in Geofencing I am facing problem. I have selected 100 meters radius and 'upon exit' notification should come. But I am getting notification on/around 250 meters. Please help me out. – Umang Kothari Feb 19 '16 at 09:27
  • 1
    Hi @UmangKothari i am facing the problem in geofencing start and exit methods are never calling,can u please give any sample codes or examples – Mahesh reddy Mar 01 '16 at 09:54
  • 1
    stackoverflow.com/questions/24165599/region-monitoring-current-location-doesnt-notify-on-exit/28315050?noredirect=1#comment59114556_28315050 – Umang Kothari Mar 01 '16 at 10:33
  • Do NOT do this. iOS Geofencing APIs does NOT require "Location updates" to be activated. If you activate this property you will need to justify it to Apple when you submit your app to the Store. This property is required to keep receiving locationUpdates in the background, so for instance if you are a fitness app it is necessary, but let me insist that for geofences only this is not needed and it is actually discouraged. – tomacco Jul 07 '20 at 14:30