CLLocationManager didUpdateLocations non appelées

Je suis en train d'apprendre le développement d'applications iOS 8 avec Swift. J'ai suivi un tutoriel sur Treehouse qui vous guide dans la construction d'une application météo dans Swift et iOS 8.

En tant qu'amélioration de l'application, l'auteur / tuteur suggère d'utiliser CLLocationManager pour get l'location du périphérique à alimenter dans l'API météo au lieu des valeurs de latitude et de longitude codées en dur.

Après avoir lu divers tutoriel en ligne, je suis allé de l'avant et a tenté de mettre en œuvre cette amélioration suggérée.

J'ai placé le code responsable d'get les coordonnées d'location dans le file AppDelegate.swift .

AppDelegate.swift Code

 import UIKit import CoreLocation @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { var window: UIWindow? var locationManager: CLLocationManager! var errorOccured: Bool = false var foundLocation: Bool = false var locationStatus: NSSsortingng = "Not Started" var location: CLLocationCoordinate2D? var locationName: Ssortingng? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. application.setStatusBarHidden(true, withAnimation: .None) initializeLocationManager() return true } func initializeLocationManager() { self.locationManager = CLLocationManager() self.locationManager.delegate = self self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer self.locationManager.requestAlwaysAuthorization() self.locationManager.startUpdatingLocation() } func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { println("didUpdateLocations running") if (foundLocation == false) { self.locationManager.stopUpdatingLocation() foundLocation = true var locationArray = locations as NSArray var locationObj = locationArray.lastObject as CLLocation var geoCoder = CLGeocoder() geoCoder.reverseGeocodeLocation(locationObj, completionHandler: { (placemarks, error) -> Void in var p = placemarks as NSArray var placemark: CLPlacemark? = p.lastObject as? CLPlacemark self.locationName = placemark?.name }) self.location = locationObj.coordinate } } func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) { locationManager.stopUpdatingLocation() if ((error) != nil) { if (errorOccured == false) { errorOccured = true print(error) } } } // authorization status func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) { var shouldIAllow = false switch status { case CLAuthorizationStatus.Ressortingcted: locationStatus = "Ressortingcted Access to location" case CLAuthorizationStatus.Denied: locationStatus = "User denied access to location" case CLAuthorizationStatus.NotDetermined: locationStatus = "Status not determined" default: locationStatus = "Allowed to location Access" shouldIAllow = true } NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil) if (shouldIAllow == true) { NSLog("Location to Allowed") // Start location services locationManager.startUpdatingLocation() } else { NSLog("Denied access: \(locationStatus)") } } } 

Et puis dans mon file ViewController.swift je veux get les coordonnées de localization. Voici le code:

ViewController.swift Code

 func getCurrentWeatherData() -> Void { let baseURL = NSURL(ssortingng: "https://api.forecast.io/forecast/\(apiKey)/") var forecastURL: NSURL var locName = "London" let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate appDelegate.foundLocation = false if let loc = appDelegate.location { println("Got Location!") // for debug purposes var currentLat = loc.latitude var currentLng = loc.longitude forecastURL = NSURL(ssortingng: "\(currentLat),\(currentLng)", relativeToURL: baseURL) locName = appDelegate.locationName! } else { println("No Location :(") // for debug purposes var currentLat = "51.513445" var currentLng = "-0.157828" forecastURL = NSURL(ssortingng: "\(currentLat),\(currentLng)", relativeToURL: baseURL) } let sharedSession = NSURLSession.sharedSession() let downloadTask: NSURLSessionDownloadTask = sharedSession.downloadTaskWithURL(forecastURL, completionHandler: { (location: NSURL!, response: NSURLResponse!, error: NSError!) -> Void in var urlContents = NSSsortingng.ssortingngWithContentsOfURL(location, encoding: NSUTF8SsortingngEncoding, error: nil) if (error == nil) { let dataObject = NSData(contentsOfURL: location) let weatherDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataObject, options: nil, error: nil) as NSDictionary let currentWeather = Current(weatherDictionary: weatherDictionary) dispatch_async(dispatch_get_main_queue(), { () -> Void in self.locationNameLabel.text = "\(locName)" self.temperatureLabel.text = "\(currentWeather.temperature)" self.iconView.image = currentWeather.icon! self.currentTimeLabel.text = "At \(currentWeather.currentTime!) it is" self.humidityLabel.text = "\(currentWeather.humidity)" self.percipitationLabel.text = "\(currentWeather.percipProbability)" self.summaryLabel.text = "\(currentWeather.summary)" // Stop refresh animation self.refreshActivityIndicator.stopAnimating() self.refreshActivityIndicator.hidden = true self.refreshButton.hidden = false }) } else { let networkIssueController = UIAlertController(title: "Error", message: "Unable to load data. Connectivity error!", preferredStyle: .Alert) let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil) networkIssueController.addAction(okButton) let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil) networkIssueController.addAction(cancelButton) self.presentViewController(networkIssueController, animated: true, completion: nil) dispatch_async(dispatch_get_main_queue(), { () -> Void in self.refreshActivityIndicator.stopAnimating() self.refreshActivityIndicator.hidden = true self.refreshButton.hidden = false }) } }) downloadTask.resume() } 

Ce qui précède ne fonctionne pas . Mon délégué didUpdateLocations n'est jamais appelé. Et dans la console de debugging / sortie, je reçois toujours No Location :( imprimé, suggérant un échec dans l'obtention de l'location, suggérant plus spécifiquement que la propriété location sur mon AppDelegate est nil .

Choses que j'ai faites pour y remédier:

  1. Dans l'info.plist j'ai ajouté les deux keys NSLocationWhenInUseUsageDescription et NSLocationAlwaysUsageDescription
  2. Assuré que je suis connecté via WiFi et non Ethernet

Et d'innombrables autres ajustements de code et des heures de déconner, et toujours rien. 🙁 Toute aide serait grandement appréciée.

Je vous remercie.

Quelques observations:

  1. Comme vous le faites remarquer, si vous appelez requestAlwaysAuthorization , vous devez définir NSLocationAlwaysUsageDescription . Si vous requestWhenInUseAuthorization , vous aurez besoin de NSLocationWhenInUseUsageDescription . (Le fait que vous voyez la boîte de dialog de confirmation signifie que vous l'avez fait correctement, je suppose que vous voyez la description que vous avez fournie dans l'alerte de confirmation.)

  2. Sur votre simulateur, il se peut que vous ne puissiez pas voir les mises à jour de localization comme sur un appareil. Testez ceci sur un périphérique réel.

    Lorsque j'ai utilisé votre code, je vois didUpdateLocations quand je l'ai appelé depuis un périphérique, mais pas depuis le simulateur.

  3. Une fois que vous avez résolu le problème de ne pas voir didUpdateLocations cours d'appel, il y a un autre problème:

    Vous envoyez une notification lorsque le statut de l'autorisation change, mais pas quand un location est reçu de manière asynchronous (c'est-à-dire plus tard). Franchement, ce dernier est l'événement le plus critique du sharepoint vue du controller de vue, donc j'aurais pensé que (a) vous devriez publier une notification lorsque le lieu est reçu; et (b) le controller de vue doit observer cette notification. À l'heure actuelle, même si vous réussissez à didUpdateLocations , le controller de vue n'en sera pas averti.

    En outre, votre didUpdateLocations initie encore un autre process asynchronous, le géoencoding de la coordonnée. Si votre controller de vue en a également besoin, vous devez publier une notification dans le bloc d'achèvement du géocodeur.

    Franchement, vous ne nous avez même pas montré le code du controller de vue qui ajoute un observateur pour toutes les notifications que ce code CLLocationManagerDelegate va invoquer, mais je suppose que vous l'avez fait.

Juste pour le count rendu: j'ai d'abord mis les deux keys ( NSLocationAlwaysUsageDescription et NSLocationWhenInUseUsageDescription ) dans le test-plist au lieu de l' application-plist . J'ai pris un peu de time pour réaliser …..