Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

locationManager(_:​did​Change​Authorization:​) executes when app first runs?

Does location​Manager(_:​did​Change​Authorization:​) get called whenever an app first runs, even if neither location manager method requestWhenInUseAuthorization() or startUpdatingLocation() has been called? I'm trying to report location at the click of a button which I call in the @IBAction below:

@IBAction func findOutPressed(_ sender: UIButton) {
    getLocation()
}

My CoreLocation code is in the extension below:

extension ViewController: CLLocationManagerDelegate {
    
    // Called from findOutPressed to get location when button is clicked
    func getLocation() {
        let status = CLLocationManager.authorizationStatus()
        handleLocationAuthorizationStatus(status: status)
    }
    
    // Respond to the result of the location manager authorization status
    func handleLocationAuthorizationStatus(status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            locationManager.requestWhenInUseAuthorization()
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.startUpdatingLocation()
        case .denied:
            print("I'm sorry - I can't show location. User has not authorized it")
        case .restricted:
            print("Access denied - likely parental controls are restricting use in this app.")
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        handleLocationAuthorizationStatus(status: status)
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        let currentLocation = locations.last
        
        let labelText = "My location is: latitude = \((currentLocation?.coordinate.latitude)!), longitude = \((currentLocation?.coordinate.longitude)!)"
        
        resultLabel.text = labelText
        
        locationManager.stopUpdatingLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print("Dang, there was an error! Error: \(error)")
    }
}

I'm finding location​Manager(did​Change​Authorization:​) is executing right away, even if the @IBAction findOutPressed hasn't been triggered with a click, and the results are being updated in my initially-blank resultsLabel before the user has clicked the button. I know I can set a flag to determine if the button was clicked or not, preventing the label from updating pre-maturely, but I'm trying to understand when location​Manager(_:​did​Change​Authorization) is triggered. Apple says: "This method is called whenever the application’s ability to use location services changes. Changes can occur because the user allowed or denied the use of location services for your application or for the system as a whole." It doesn't seem this covers the case of triggering when an app first runs. I'm grateful for anyone who can set me straight in my understanding of what's happening with authorization changes. Apologies if I've missed something basic. Thanks!

like image 313
Gallaugher Avatar asked Dec 23 '22 19:12

Gallaugher


1 Answers

didChangeAuthorization is called when the CLLocationManager is created, so even this will trigger:

var locationManager = CLLocationManager()
// ...
locationManager?.delegate = self
// ...
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    print( "authorization checked..." )
}

So you probably are setting & initializing your locationManager at the top of AppDelegate? That would trigger it. Then what happens is that the didChangeAuthorization starts updating location which then winds up calling your didUpudateLocation before the button was actually tapped.

Maybe declare locationManager as an optional and only init in findOutPressed() e.g.:

// class var:
var locationManager:CLLocationManager?location managers,
// ...
@IBAction func findOutPressed(_ sender: UIButton) {
    locationManager = CLLocationManager()
    locationManager?.delegate = self

    getLocation()
}
like image 109
hungri-yeti Avatar answered May 04 '23 18:05

hungri-yeti