所以我想在用户点击按钮时收集用户位置,并稍后在我的应用程序中使用该位置。在我当前的实现中,当点击按钮时,应该提示用户允许共享位置,然后他们应该登录到应用程序(如果你想知道的话,通过 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
文档中,我看到与您声明的 didUpdateLocations
和 didFailWithError
方法不同:
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/