web-dev-qa-db-fra.com

Swift LocationManager didChangeAuthorizationStatus toujours appelé

J'ai un contrôleur de vue qui implémente le CLLocationManagerDelegate. Je crée une variable CLLocationManager:

let locationManager = CLLocationManager()

Puis dans le viewDidLoad, je définis les propriétés:

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

Le problème vient que la fonction est appelée avant même que je vérifie l'état d'autorisation.

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

Quelqu'un peut-il m'informer de ce qui pourrait provoquer ce problème?

26
Mike Walker

- locationManager:didChangeAuthorizationStatus: est appelé peu de temps après l'initialisation de CLLocationManager.

Vous pouvez demander une autorisation à l'intérieur de la méthode déléguée si vous souhaitez:

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
    }
}

Sachez que vous devez affecter le délégué en temps opportun si vous voulez que cela fonctionne.

Si vous retardiez d'une manière ou d'une autre l'affectation du délégué, par ex. en le définissant de manière asynchrone, vous risquez de manquer l'appel initial à - locationManager:didChangeAuthorizationStatus:.

48

Swift

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
        }
    }
6
Vyacheslav

Les autres réponses pourraient introduire de nouveaux comportements indésirables.

Vous pouvez simplement ajouter un booléen et un garde pour empêcher le premier appel, avec quelques commentaires expliquant le bogue:

var firstTimeCalled = true

// ...    

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

    guard !firstTimeCalled else {
        firstTimeCalled = false
        return
    }

    // ... send status to listeners
}
0
Xys