Mike Walker
Mike Walker

Reputation: 3176

Swift LocationManager didChangeAuthorizationStatus Always Called

I have a view controller which implements the CLLocationManagerDelegate. I create a the CLLocationManager variable:

let locationManager = CLLocationManager()

Then in the viewDidLoad, I set properties:

// Set location manager properties
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.distanceFilter = 50

The problem comes that the function gets called even before I check the authorization status.

func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    if (status == .AuthorizedWhenInUse) {
        // User has granted autorization to location, get location
        locationManager.startUpdatingLocation()
    }
}

Can anyone inform me what could be causing this to occur?

Upvotes: 33

Views: 19158

Answers (3)

Bart Vandendriessche
Bart Vandendriessche

Reputation: 1392

- locationManager:didChangeAuthorizationStatus: is called shortly after the CLLocationManager is initialised.

You can request authorization inside the delegate method if you want:

func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    switch status {
    case .notDetermined:
        locationManager.requestAlwaysAuthorization()
        break
    case .authorizedWhenInUse:
        locationManager.startUpdatingLocation()
        break
    case .authorizedAlways:
        locationManager.startUpdatingLocation()
        break
    case .restricted:
        // restricted by e.g. parental controls. User can't enable Location Services
        break
    case .denied:
        // user denied your app access to Location Services, but can grant access from Settings.app
        break
    default:
        break
    }
}

Be aware that you need to assign the delegate in a 'timely' matter if you want this to work.

If you would somehow delay the delegate assignment, e.g. by setting it asynchronously, you might miss the initial call to - locationManager:didChangeAuthorizationStatus:.

Upvotes: 59

Xys
Xys

Reputation: 10921

The other answers could introduce new undesirable behaviors.

You can just add a boolean and a guard to prevent the first call, with some comments explaining the bug :

var firstTimeCalled = true

// ...    

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

    guard !firstTimeCalled else {
        firstTimeCalled = false
        return
    }

    // ... send status to listeners
}

Upvotes: 3

Vyacheslav
Vyacheslav

Reputation: 27221

Swift 3

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .notDetermined:
            manager.requestAlwaysAuthorization()
            break
        case .authorizedWhenInUse:
            manager.startUpdatingLocation()
            break
        case .authorizedAlways:
            manager.startUpdatingLocation()
            break
        case .restricted:
            // restricted by e.g. parental controls. User can't enable Location Services
            break
        case .denied:
            // user denied your app access to Location Services, but can grant access from Settings.app
            break
        }
    }

Upvotes: 7

Related Questions