Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Location Manager didExitRegion not being called

I've set the delegate, created a region and i've read all the documentation. Every time the user's location changes and is outside of the specified region, locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) isn't being called. I've seen it get called once and then it stopped doing it. I've spent a lot of time trying to figure out what's going on.

Quick overview of what i'm doing:

When the app launches I call locationManager.startUpdatingLocation() which in turn calls the delegates locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]), I do a quick request to the server with some information I need, create a CLCircularRegion and proceed to call locationManager.stopUpdatingLocation(). In that method I call my startMonitoringForRegion(_:).

Is it maybe because every time I create a new region it uses the same identifier? Apple's docs say it's okay to use the same identifier, because it will replace the previous one, but I'm wondering if that's causing the delegate not to call didExitRegion.

My code is below. Thank you.

  func configureLocation() {

    if CLLocationManager.locationServicesEnabled() {

        locationManager.delegate = self

        locationManager.requestAlwaysAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.allowsBackgroundLocationUpdates = false
        locationManager.pausesLocationUpdatesAutomatically = true

        // Distance filter to update location
        //locationManager.distanceFilter = 10.0

        // Begin updating user location
        locationManager.startUpdatingLocation()

    } else {

        let title = "Location disabled"
        let message = "To enable location services go to Settings > Privacy > Location Services"
        self.locationServicesAlertMessage(title, message: message)
    }
}


func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("didUpdateCalled")
    /*
    if UIApplication.sharedApplication().applicationState == .Active {
        print("ACTIVE UPDATE: location")
    } else if UIApplication.sharedApplication().applicationState == .Background {
        print("BACKGROUND UPDATE: location")
    }
    */

    if firstLocationUpdate {
        let center = CLLocationCoordinate2D(latitude: (manager.location?.coordinate.latitude)!, longitude: (manager.location?.coordinate.longitude)!)
        let region = MKCoordinateRegion(center: center, span: MKCoordinateSpanMake(0.01, 0.01))

        self.mapView.setRegion(region, animated: true)

        self.firstLocationUpdate = false
    }


    // If the user is travelling less than 5 mph, update location
    if manager.location?.speed <= 3.5 {

        self.updateLongAndLat(manager.location!) { (lat, long) in

            print("LAT: \(lat)")
            print("LONG: \(long)")
            if lat != nil && long != nil {
                let center = CLLocationCoordinate2D(latitude: lat!, longitude: long!)
                let monitoredRegion = CLCircularRegion(center: center, radius: 10.0, identifier: "UserRegion")
                monitoredRegion.notifyOnEntry = false
                self.locationManager.startMonitoringForRegion(monitoredRegion)
                self.locationManager.stopUpdatingLocation()
            }
        }
    }
}

func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
    print("EXITED REGION")

    print("Identifier: \(region.identifier)")
    if manager.location?.speed <= 3.5 {
        self.updateLongAndLat(manager.location!, completion: { (lat, long) in
            if lat != nil && long != nil {
                let center = CLLocationCoordinate2D(latitude: lat!, longitude: long!)
                let monitoredRegion = CLCircularRegion(center: center, radius: 10.0, identifier: "UserRegion")
                self.locationManager.startMonitoringForRegion(monitoredRegion)
            }
        })
    }
}
like image 958
Mihado Avatar asked Apr 07 '16 20:04

Mihado


1 Answers

Region monitoring does not rely upon GPS. It is cell tower/wifi access point triangulation. You should not expect horizontal accuracy better than 65m. Trying to detect 10m movements with 65m accurate instrument simply does not work.

I do not know what iOS does when being requested to monitor regions with radius less than 100m. At best it just bumps radius to 100. In this case your app will still work, but probably not the way it was intended to.

To answer your question from comments, I am afraid Apple does not provide deep insights into their core location technology. That's the reason for a lot of confusion among developers, as nothing seems to work as expected. For starters, the core location API is designed to enforce good practices for minimizing battery consumption.

If you want to use location services finer than ~300m (yes, three hundred), you have to use GPS. Geofencing will not keep up pace with constantly walking user. But it is not OK to use GPS constantly running in background, as you are going to deplete battery pretty fast and your app is going to be expelled from user phone in no time.

Geofencing does not require GPS, but will gladly use GPS data if available (even if GPS updates were requested by another app). GPS assisted geofencing works amazingly precise, but I do not see any good reasons to use both services together, as it simpler just to set location manager filter to the right distance.

like image 150
Alex Pavlov Avatar answered Oct 24 '22 02:10

Alex Pavlov