所以我想在用户点击按钮时收集用户位置,并稍后在我的应用中使用该位置。使用我当前的实现,当点击按钮时,应该提示用户允许共享位置,然后他们应该登录到应用程序(如果您想知道的话,通过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)
}
}
答案 0 :(得分:9)
首先,明确添加您确认CLLocationManagerDelegate
:
class LoginViewController: UIViewController, CLLocationManagerDelegate
其次,为CLLocationManager
设置委托属性:
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
ref = FIRDatabase.database().reference()
}
第三,在CLLocationManagerDelegate
doc中,我发现与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
当您第一次调用此函数时,您的位置尚未确定(将以异步方式确定,您将获得委托方法中的位置),这就是使用force unwrapp时出现致命错误的原因。在didUpdateLocations
函数中:
if let pm = placemarks?.first
{
self.displayLocationInfo(pm)
}
这部分代码的修正比原始代码短,并且可以防止您同时发生两次可能的崩溃 - 当placemarks
为零并且placemarks
不是nil时,但是空数组< / p>