错误:'代表必须响应locationManager:didUpdateLocations:'收集用户位置时

时间:2016-06-22 13:04:48

标签: swift mapkit core-location

所以我想在用户点击按钮时收集用户位置,并稍后在我的应用中使用该位置。使用我当前的实现,当点击按钮时,应该提示用户允许共享位置,然后他们应该登录到应用程序(如果您想知道的话,通过Firebase匿名),并且应该打印用户位置信息到控制台。提示有效,但是在点击允许位置按钮后,我的应用程序终止due to uncaught exception 'NSInternalInconsistencyException'

原因是'Delegate must respond to locationManager:didUpdateLocations:'

这很奇怪,因为我的代码中有didUpdateLocations:函数。

我不知道发生了什么,任何帮助都表示赞赏。我的ViewController代码如下,谢谢!

/*
* Copyright (c) 2016 Ahad Sheriff
*
*/

import UIKit
import Firebase
import CoreLocation

class LoginViewController: UIViewController {

    // MARK: Properties
    var ref: FIRDatabaseReference! // 1
    var userID: String = ""

    var locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        ref = FIRDatabase.database().reference() // 2
    }

    @IBAction func loginDidTouch(sender: AnyObject) {

        //ask user to enable location services
        locationManager.requestWhenInUseAuthorization()

        if CLLocationManager.locationServicesEnabled() {
            //collect user's location
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
            locationManager.requestLocation()
            locationManager.startUpdatingLocation()

            let location = self.locationManager.location

            var latitude: Double = location!.coordinate.latitude
            var longitude: Double = location!.coordinate.longitude

            print("current latitude :: \(latitude)")
            print("current longitude :: \(longitude)")

            //Log in to application anonymously using Firebase
            FIRAuth.auth()?.signInAnonymouslyWithCompletion() { (user, error) in
                if let user = user {
                    print("User is signed in with uid: ", user.uid)
                    self.userID = user.uid
                } else {
                    print("No user is signed in.")
                }

                self.performSegueWithIdentifier("LoginToChat", sender: nil)

            }

        }

        else {
            print("Unable to determine location")
        }

    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        super.prepareForSegue(segue, sender: sender)
        let navVc = segue.destinationViewController as! UINavigationController // 1
        let chatVc = navVc.viewControllers.first as! ChatViewController // 2
        chatVc.senderId = userID // 3
        chatVc.senderDisplayName = "" // 4
    }

    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!)
    {
        //--- CLGeocode to get address of current location ---//
        CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in

            if (error != nil)
            {
                print("Reverse geocoder failed with error" + error!.localizedDescription)
                return
            }

            if placemarks!.count > 0
            {
                let pm = placemarks![0] as CLPlacemark
                self.displayLocationInfo(pm)
            }
            else
            {
                print("Problem with the data received from geocoder")
            }
        })

    }


    func displayLocationInfo(placemark: CLPlacemark?)
    {
        if let containsPlacemark = placemark
        {
            //stop updating location
            locationManager.stopUpdatingLocation()

            let locality = (containsPlacemark.locality != nil) ? containsPlacemark.locality : ""
            let postalCode = (containsPlacemark.postalCode != nil) ? containsPlacemark.postalCode : ""
            let administrativeArea = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea : ""
            let country = (containsPlacemark.country != nil) ? containsPlacemark.country : ""

            print(locality)
            print(postalCode)
            print(administrativeArea)
            print(country)
        }

    }


    func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
        print("Error while updating location " + error.localizedDescription)
    }


}

1 个答案:

答案 0 :(得分:9)

首先,明确添加您确认CLLocationManagerDelegate

class LoginViewController: UIViewController, CLLocationManagerDelegate

其次,为CLLocationManager设置委托属性:

override func viewDidLoad() {
    super.viewDidLoad()
    locationManager.delegate = self
    ref = FIRDatabase.database().reference()
}

第三,在CLLocationManagerDelegate doc中,我发现与didUpdateLocationsdidFailWithError方法的声明不同:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
func locationManager(_ manager: CLLocationManager, didFailWithError error: NSError)

此外,您在代码中几乎没有其他问题。它们都是关于不安全的展开。你不应该在任何地方使用不安全的展开!。这样做是为了杀死选择哲学。另一方面,做正确的事情可以大大提高应用的稳定性。在loginDidTouch函数中进行以下更正:

var latitude: Double? = location?.coordinate.latitude
var longitude: Double? = location?.coordinate.longitude

当您第一次调用此函数时,您的位置尚未确定(将以异步方式确定,您将获得委托方法中的位置),这就是使用force unwrapp时出现致命错误的原因。在didUpdateLocations函数中:

if let pm = placemarks?.first
{
    self.displayLocationInfo(pm)  
}

这部分代码的修正比原始代码短,并且可以防止您同时发生两次可能的崩溃 - 当placemarks为零并且placemarks不是nil时,但是空数组< / p>