0

I am trying to implement directions with clLocationManager in a project. Everything is working ok, but the didEnterrRegion function is very slow to fire. When testing, I enter the region but only 2-3 minutes after exiting the region I get the callback. Does anyone have any suggestion on how to improve this? This is the locationManager:

    private lazy var locationManager: CLLocationManager = {
        let locationManager = CLLocationManager()
        
        if CLLocationManager.locationServicesEnabled() {
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
            locationManager.distanceFilter = kCLDistanceFilterNone
            handleAuthorizationStatus(locationManager: locationManager)
            
        } else {
            //TODO: Handle error
        }
        return locationManager
    }()

This is which regions I am tracking, here I am also drawing each region to easier see when I enter specific region:

    private func getRouteSteps(_ mapView: MKMapView, route: MKRoute) {
        for monitoredRegion in locationManager.monitoredRegions {
            locationManager.stopMonitoring(for: monitoredRegion)
        }
        
        let steps = route.steps
        self.steps = steps
        
        for i in 0..<steps.count {
            let step = steps[i]
            let region = CLCircularRegion(center: step.polyline.coordinate, radius: 30, identifier: "\(i)")
            let circle = MKCircle(center: region.center, radius: region.radius)
            mapView.addOverlay(circle)
            locationManager.startMonitoring(for: region)
        }
        
        stepCounter += 1
        let initialMessage = "Om \(Int(steps[stepCounter].distance)) meter \(steps[stepCounter].instructions.lowercased())"
        directionMessage = initialMessage
    }

This is the locationManager-function:

extension MapViewModel: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        //        manager.stopUpdatingLocation()
        if directionsViewState != .isShowingRoute {
            if let location = locations.last {
                self.didUpdateRegion = "Updated region with accuracy: \(location.horizontalAccuracy)"
                let center = location.coordinate
                setNewRegionForMapView(center: center)
                isCenteringUserLocation = true
            }
        }
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        handleAuthorizationStatus(locationManager: locationManager)
    }
    
    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
        self.didEnterregion = "Entered region: \(region.identifier)"
        stepCounter += 1
        if stepCounter < steps.count {
            let message = "Om \(Int(steps[stepCounter].distance)) meter \(steps[stepCounter].instructions.lowercased())"
            directionMessage = message
            let speechUtterance = AVSpeechUtterance(string: message)
            speechSynthesizer.speak(speechUtterance)
        } else {
            directionMessage = "You have arrived at your destination!"
            stepCounter = 0
            let speechUtterance = AVSpeechUtterance(string: directionMessage)
            speechSynthesizer.speak(speechUtterance)
            for monitoredRegion in locationManager.monitoredRegions {
                locationManager.stopMonitoring(for: monitoredRegion)
            }
        }
    }
}

I am also calling locationManager.startUpdatingLocations in the init-method.

1 Answers1

0

Suppose that you are using locationManager.requestWhenInUseAuthorization().

So, I have some suggestions for you:

  • [METHOD 1] Apply background location updating: Enable background mode to your target

    Then add these lines of code:

    locationManager.allowsBackgroundLocationUpdates = true
    locationManager.pausesLocationUpdatesAutomatically = false
    

    The line allowsBackgroundLocationUpdates = true will allow your app to run in the background to receive new location event (ex: lock screen, use another app,...).

    And, pausesLocationUpdatesAutomatically = false will tell the system to not pause location updating, system can pause background location updating to save battery.

    Call your locationManager.startUpdatingLocation() to start listening for new location change.

  • Next [METHOD 2], if above method doesn't work, you can switch to use locationManager.requestAlwaysAuthorization(). Its description is Requests the user’s permission to use location services regardless of whether the app is in use. System can wake your app to run in background to handle new location events. Remember to add the permission description for requestAlwaysAuthorization in Info.plist file.

  • Next [METHOD 3], try to increase your CLCircularRegion's radius to higher value, ex: 50 meters. Or you can try to increase the distanceFilter to 2 meters, distanceFilter = none isn't a best option.

  • Finally [METHOD 4], Make your customized region monitoring logic by calculating distance from user's location to region's center whenever we get a new location event, use this one func distance(from location: CLLocation) -> CLLocationDistance. If distance is <= your region's radius, that means user already crossed the boundary.

Hope that you can solve your problem.

Neklas
  • 504
  • 1
  • 9
  • Thanks for the suggestions. While testing all of this I am setting a text on the screen every time the location updates and the same for when I enter a monitored region. I get updates frequently so that doesn't seem to be an issue. I also tried to set the region radius to various values between 1-50 and all gave similar result. I appreciate the suggestion anyway! I will keep tring. – Olle Hammar May 25 '22 at 05:54
  • @OlleHammar Hope you solved your issue. For [METHOD 4], you will need to modify your logic in: `func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])` And, skip this function because it is slow updating. `func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion)` – Neklas Sep 02 '22 at 12:31