CLLocationManager didUpdateLocations не вызывается

Я участвую в процессе разработки приложений для iOS 8 с помощью Swift. Я следил за учебником по Treehouse, который проводит вас через создание приложения погоды в Swift и iOS 8.

В качестве улучшения для приложения автор / наставник предлагает использовать CLLocationManager чтобы получить местоположение устройства для подачи в API погоды, а не на жесткие кодированные значения широты и долготы.

Поэтому, прочитав различные учебники онлайн, я пошел дальше и попытался реализовать это предлагаемое улучшение.

Я поместил код, ответственный за получение координат местоположения внутри файла AppDelegate.swift .

Код AppDelegate.swift

 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: NSString = "Not Started" var location: CLLocationCoordinate2D? var locationName: String? 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.Restricted: locationStatus = "Restricted 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)") } } } 

И затем в моем файле ViewController.swift я хочу получить координаты местоположения. Вот код:

Код ViewController.swift

 func getCurrentWeatherData() -> Void { let baseURL = NSURL(string: "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(string: "\(currentLat),\(currentLng)", relativeToURL: baseURL) locName = appDelegate.locationName! } else { println("No Location :(") // for debug purposes var currentLat = "51.513445" var currentLng = "-0.157828" forecastURL = NSURL(string: "\(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 = NSString.stringWithContentsOfURL(location, encoding: NSUTF8StringEncoding, 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() } для func getCurrentWeatherData() -> Void { let baseURL = NSURL(string: "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(string: "\(currentLat),\(currentLng)", relativeToURL: baseURL) locName = appDelegate.locationName! } else { println("No Location :(") // for debug purposes var currentLat = "51.513445" var currentLng = "-0.157828" forecastURL = NSURL(string: "\(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 = NSString.stringWithContentsOfURL(location, encoding: NSUTF8StringEncoding, 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() } 

Вышеуказанное не работает . Мой делегат didUpdateLocations никогда не didUpdateLocations . И в консоли отладки / вывода я всегда получаю No Location :( распечатанный, предлагая ошибку в получении местоположения, более конкретно предлагая, что свойство location в моем AppDelegate равно nil .

Что я сделал, чтобы исправить это:

  1. В info.plist я добавил два ключа NSLocationWhenInUseUsageDescription и NSLocationAlwaysUsageDescription
  2. Убедитесь, что я подключен через Wi-Fi, а не через Ethernet

И бесчисленное множество других кодовых трюков и часов беспорядков, и все равно ничего. 🙁 Любая помощь будет принята с благодарностью.

Спасибо.

Несколько замечаний:

  1. Как вы NSLocationAlwaysUsageDescription , если вы собираетесь вызвать requestAlwaysAuthorization , тогда вы должны установить NSLocationAlwaysUsageDescription . Если вы вызвали requestWhenInUseAuthorization , вам понадобится NSLocationWhenInUseUsageDescription . (Тот факт, что вы видите диалоговое окно подтверждения, означает, что вы сделали это правильно. Я предполагаю, что вы видите, какое описание вы указали в предупреждении о подтверждении.)

  2. На вашем симуляторе вы можете не видеть обновления местоположения, как на устройстве. Проверьте это на самом устройстве.

    Когда я использовал ваш код, я вижу didUpdateLocations когда я вызывал это с устройства, но не из симулятора.

  3. После того, как вы решите проблему не видя, что вызываемые didUpdateLocations , есть еще одна проблема:

    Вы отправляете уведомление, когда статус авторизации изменяется, но не тогда, когда местоположение получено асинхронно (т.е. позже). Честно говоря, последнее является более критическим событием с точки зрения контроллера зрения, поэтому я бы подумал, что (а) вы должны отправить уведомление, когда оно будет получено; и (б) контроллер просмотра должен наблюдать это уведомление. Прямо сейчас, даже если вам удастся получить didUpdateLocations для didUpdateLocations , контроллер вида не будет уведомлен о таком.

    Кроме того, ваши didUpdateLocations инициируют еще один асинхронный процесс – геокод координаты. Если вам нужен диспетчер просмотра, вы также должны отправить уведомление внутри блока завершения геокодирования.

    Честно говоря, вы даже не CLLocationManagerDelegate нам код контроллера вида, который добавляет наблюдателя для любых уведомлений, которые этот код CLLocationManagerDelegate будет вызывать, но я предполагаю, что вы это сделали.

Только для записи: я сначала положил два ключа ( NSLocationAlwaysUsageDescription и NSLocationWhenInUseUsageDescription ) в test-plist вместо application-plist plist. Пришло время понять …..

  • Каково максимальное количество регионов, которые можно отслеживать с помощью startMonitoringForRegion: region wishAccuracy: точность?
  • Поверните GMSMarker в направлении, с которым пользователь сталкивается
  • Действительно ли работаетMonitoringForRegion?
  • CLCircularRegion - произвольное значение для notifyOnEntry
  • Ошибка: присвоение 'CLLocationCoordinate2D' из несовместимого типа 'id'
  • Следует ли мне избегать пользовательского интерфейса, когда приложение iOS запускается в фоновом режиме
  • CLRocationManager's didExitRegion никогда не вызывается
  • Как включить доступ к службе мониторинга региона?
  • Координаты CLLocationManager
  • Расстояние между 2 точками с CLLocationCoordinate2D
  • Обновляется ли обновление местоположения после приложения принудительного закрытия
  • Interesting Posts
    Давайте будем гением компьютера.