swift - 错误 : 'Delegate must respond to locationManager:didUpdateLocations:' when collecting user location

标签 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)
    }


}

最佳答案

首先,明确添加您确认CLLocationManagerDelegate:

class LoginViewController: UIViewController, CLLocationManagerDelegate

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

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

第三,在 CLLocationManagerDelegate 文档中,我看到与您声明的 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

当你第一次调用这个函数时,你的位置还没有确定(它会异步确定,你会在委托(delegate)方法中获得位置),所以当你使用强制解包时会出现 fatal error 。在 didUpdateLocations 函数中:

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

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

关于swift - 错误 : 'Delegate must respond to locationManager:didUpdateLocations:' when collecting user location,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37968933/

相关文章:

iphone - MKMapView:缩放到默认值 "country level"

ios - 如何在一周中的特定几天重复本地通知(iOS Swift 3)

ios - 如何通过 Segue 将变量从子类传递到 SecondViewController

iphone - 如何从 iPhone 中的地址查找纬度和经度

ios - CLLocationManager reverseGeocodeLocation 语言

ios - 在使用 Xcode 9 为 iOS 11 设备构建的应用程序上出现间歇性和延迟的重要位置更改事件

ios - 使用 .childAdded 类型的 Firebase observe 每次都会检索我的所有信息。请协助

javascript - 在Swift中使用JS隐藏WKWebView集合元素

ios - 解散时如何从模态视图 Controller 传回数据

iphone - 使用mapkit计算两个地址之间的行驶距离?