CLLocationManager didUpdateLocations不被调用

我正在用Swift学习iOS 8应用程序的开发过程。 我遵循了一个关于Treehouse的教程,它引导您在Swift和iOS 8中构build天气应用程序。

作为应用程序的改进,作者/导师build议使用CLLocationManager来获取设备的位置,以便将其馈入天气API,而不是硬编码的经度和纬度值。

所以在网上阅读各种教程,我已经走了,试图实现这个build议的改进。

我已经将代码负责获取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() } 

以上是不行的 。 我didUpdateLocations委托永远不会被调用。 并在debugging控制台/输出我总是得到No Location :(打印出来,build议在获取位置失败,更具体地build议我的AppDelegate的位置属性nil

事情我做了补救措施:

  1. 在info.plist中,我添加了两个键NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription
  2. 确保我通过WiFi而不是以太网连接

无数其他的代码调整和几个小时的混乱,而且什么也没有。 :( 任何帮助将不胜感激。

谢谢。

几点意见:

  1. 正如你指出的那样,如果你打算调用requestAlwaysAuthorization ,那么你必须设置NSLocationAlwaysUsageDescription 。 如果你调用requestWhenInUseAuthorization ,你需要NSLocationWhenInUseUsageDescription 。 (事实上​​,您看到确认对话框意味着您已经正确完成了这个操作,我假定您看到了您在确认提醒中提供的任何描述。)

  2. 在您的模拟器上,您可能看不到像设备上的位置更新。 在一个实际的设备上testing这个。

    当我使用你的代码时,当我从设备调用它的时候,我看到了didUpdateLocations ,而不是从模拟器中调用。

  3. 一旦你解决了没有看到didUpdateLocations被调用的问题,还有另一个问题:

    您在授权状态更改时发布通知,但不是在asynchronous接收位置(即,稍后)时发送通知。 坦率地说,从视图控制者的angular度来看,后者是更关键的事件,所以我会认为(a)你应该在收到位置时发布通知; 和(b)视图控制器应该观察这个通知。 现在,即使您成功地调用了didUpdateLocations ,视图控制器也不会被通知。

    此外,您的didUpdateLocations正在启动另一个asynchronous过程,坐标的地理编码。 如果您的视图控制器也需要,您应该在地理编码器的完成块内发布通知。

    坦率地说,你甚至没有向我们展示过视图控制器代码,它为这个CLLocationManagerDelegate代码将会调用的任何通知添加了一个观察者,但是我假设你已经这么做了。

只是为了logging:我首先将两个键( NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription )放到test-plist而不是application-plist 。我花了一些时间来实现…..