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

Posted

技术标签:

【中文标题】错误:收集用户位置时,“代表必须响应 locationManager:didUpdateLocations:”【英文标题】:Error: 'Delegate must respond to locationManager:didUpdateLocations:' when collecting user location 【发布时间】:2016-06-22 13:04:48 【问题描述】:

所以我想在用户点击按钮时收集用户位置,并稍后在我的应用中使用该位置。在我当前的实现中,当点击按钮时,应该提示用户允许共享位置,然后他们应该登录到应用程序(如果您想知道,可以匿名通过 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】:

首先,明确添加您确认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

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

if let pm = placemarks?.first

    self.displayLocationInfo(pm)  

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

【讨论】:

谢谢,但是当我添加您建议的更改并运行应用程序时,我收到了fatal error: unexpectedly found nil while unwrapping an Optional value 另外,如果在设置 locationManager.delegate = self 之前调用 locationManager.requestLocation(),也会出现此错误。

以上是关于错误:收集用户位置时,“代表必须响应 locationManager:didUpdateLocations:”的主要内容,如果未能解决你的问题,请参考以下文章

根据 lat 和 long 得到错误的排序距离

使用空数组添加新用户记录时出现“E11000 重复键错误收集”

Flutter 应用程序可以在后台运行吗?

提示询问用户是不是要继续让您的应用收集后台位置 - 这种情况多久发生一次?

iOS 10 下后台位置和加速度计更新

Bot 不等待反应,并且由于 Emded 错误而在收集时不发送消息