【问题标题】:CLLocationManager didUpdateLocations not being called未调用 CLLocationManager didUpdateLocations
【发布时间】:2014-10-05 09:46:42
【问题描述】:

我正在学习使用 Swift 开发 iOS 8 应用程序。我已经按照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()
}

以上内容不起作用。我的didUpdateLocations 代表永远不会被调用。在调试控制台/输出中,我总是打印出No Location :(,这表明获取位置失败,更具体地说,我的AppDelegate 上的位置属性是nil

我为解决这个问题所做的事情:

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

还有无数其他代码调整,但仍然一无所获。

【问题讨论】:

  • 抱歉,我不认识 Swift。但是 LocationManager 的一个常见错误是忘记保留它。你的 var 保留了吗?
  • hmm 之前没听说过,retained 是什么意思?如您所见,它只是文件顶部的var
  • 是否请求读取位置的权限?
  • 是的,在 iOS 模拟器中它确实要求使用权限。
  • 很抱歉问了些琐碎的问题,但是:您在真机上试过吗?你在模拟器中设置了位置吗?你试过重置模拟器吗?

标签: ios swift coordinates cllocationmanager


【解决方案1】:

几个观察:

  1. 正如你所指出的,如果你要调用requestAlwaysAuthorization,那么你必须设置NSLocationAlwaysUsageDescription。如果你打电话给requestWhenInUseAuthorization,你需要NSLocationWhenInUseUsageDescription。 (您看到确认对话框的事实意味着您已正确完成此操作。我假设您看到了您在确认警报中提供的任何描述。)

  2. 在您的模拟器上,您可能不会像在设备上那样看到位置更新。在实际设备上进行测试。

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

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

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

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

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

【讨论】:

  • 谢谢 Rob,我认为第 2 点可能是这样。我是否认为我需要成为一名 Apple 开发人员(付费)才能在我的 iPhone 上进行测试?
【解决方案2】:

仅作记录:我首先将两个键(NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription)放入 test-plist 而不是 application-plist..我花了一些时间才意识到.....

【讨论】:

  • 谢谢,我会确保我回家后没有这样做。
猜你喜欢
  • 2016-07-11
  • 1970-01-01
  • 2016-05-29
  • 1970-01-01
  • 1970-01-01
  • 2013-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多