Ahad Sheriff Ahad Sheriff - 2 years ago 171
Swift Question

Error: 'Delegate must respond to locationManager:didUpdateLocations:' when collecting user location

So I want to collect user location when a user tap's a button, and use that location later on in my app. With my current implementation, when the button is tapped, the user should be prompted to allow location to be shared and then they should be logged in to the app (anonymously via Firebase in case you are wondering), and the users location information should print to the console. The prompt works, however after the allow location button is hit, my application terminates

due to uncaught exception 'NSInternalInconsistencyException'

and the reason is that the
'Delegate must respond to locationManager:didUpdateLocations:'

Which is strange because I do have a
function in my code.

I have no idea what is going on, and any help is appreciated. My ViewController code is below, thanks!

* 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() {
ref = FIRDatabase.database().reference() // 2

@IBAction func loginDidTouch(sender: AnyObject) {

//ask user to enable location services

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

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)

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


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

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 : ""



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


Answer Source

First, add explicitly that you confirm CLLocationManagerDelegate:

class LoginViewController: UIViewController, CLLocationManagerDelegate

Second, set up delegate property for CLLocationManager:

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

Third, in CLLocationManagerDelegate doc I see different from your declaration of didUpdateLocations and didFailWithError method:

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

Also, you have few other issues in code. They are all about unsafe unwrapping. You should not use unsafe unwrapping ! everywhere. Doing this you are killing optionals philosophy. Doing right thing, on other hand, can drastically increase stability of your app. In loginDidTouch function make following corrections:

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

When you call this function first time, your location not determined yet (it will be determined asynchronously, you will get location in delegate method), thats why you have fatal error when used force unwrapp. In didUpdateLocations function:

if let pm = placemarks?.first

correction of this part of code is shorter then your original code, and prevents you from two possible crashes at one time - when placemarks is nil and when placemarks is not nil, but empty array

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download