27

I've been trying to get this to work for awhile now, and I've come here to ask- how do I go about with using the CLLocationManagerDelegate methods in Swift? I've put this at the top of my class:

var locationManager = CLLocationManager()

I've put the following into my viewDidLoad method:

locationManager.delegate = self
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()

And I've tried using these delegate methods with no avail:

func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
    locationReceived = true
}

func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
    locationReceived = false
}

I've also tried using @optional in front of the functions, but Xcode then throws a compiler error. Any ideas?

  • It seems to work for me with your code, do you get the dialog asking if your app can use your location? – voidref Jun 05 '14 at 02:59
  • @voidref Now that you mention it, I'm not getting the dialog. That's a little odd... I just checked settings and the app is given permission to location access as well. –  Jun 05 '14 at 03:08

5 Answers5

58

You need to add the NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key to your plist if you haven't already, they are now mandatory,


iOS8+ requires one of these two strings to be set to use locations. Which one you use depends on how you intend ask for the location.

  • Use NSLocationAlwaysUsageDescription for apps that want to use the device's location even when the app is not open and being used.

  • Use NSLocationWhenInUseUsageDescription for apps that want to use the device's location only when the app is open and in use.

Note: When you add the strings, before you build and run, delete the app off your device and let it do a fresh install. It seems that if the app was authorized to use locations before you upgraded to iOS8 it doesn’t ask for your permission again and doesn’t see that you set those strings. Doing a delete and clean install solves this.

Setting either of the strings prompts a pop up on install/first use along the lines of: "Allow "ThisApp" to access your location even when you are not using the App"

Here's a Screenshot of the plist file.

enter image description here

Wesley Smith
  • 19,401
  • 22
  • 85
  • 133
  • [You mean like this](http://imgur.com/5CA1tKK)? That hasn't made the dialog appear either. –  Jun 05 '14 at 11:07
  • 1
    No, apparently iOS8 requires one of these other two strings to be set (see my edit). Which one you use is supposed to be based on how you intend ask for the location from what I understand but I couldnt find any more specific information. In the interest of full disclosure I still havent gotten mine working even after adding the strings as shown (my problem seems to be elsewhere Im trying to get mine running without swift at the moment), I just wanted to mention the strings since the are now required. – Wesley Smith Jun 06 '14 at 07:37
  • also, when you add the strings, before you build and run, delete the app off your device and let it do a fresh install. It seems that if the app was authorized to use locations before you upgraded to iOS8 it doesnt ask for your permission again and doesnt see that you set those strings. Doing a delete and clean install solved it for me, finally working again! – Wesley Smith Jun 06 '14 at 08:17
  • `NSLocationAlwaysUsageDescription` seems to be for apps that want to use the device's location even when the app is not open and being used . That said, setting either of the strings prompts a pop up on install for me that states: "Allow "ThisApp" to access your location even when you are not using the App" ....which seems odd. – Wesley Smith Jun 06 '14 at 20:23
  • 2
    add this to info.plist NSLocationUsageDescription Your message NSLocationAlwaysUsageDescription Your message NSLocationWhenInUsageDescription Your message – avalla Jun 12 '14 at 13:35
  • 3
    info.plist keys are: NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription ... getting these spelt correctly make a difference. This is documented in the CLLocationManager documentation - search on this text. After I corrected this my app worked - asking for permission when the procedure was called. – David Wilson Jun 24 '14 at 09:40
  • @DavidWilson Ah yep, I missed the "Use" in `NSLocationWhenInUseUsageDescription`, thanks! – Wesley Smith Jun 28 '14 at 07:35
7

First add this two line in plist file

1) NSLocationWhenInUseUsageDescription

2) NSLocationAlwaysUsageDescription

import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate

var seenError : Bool = false
var locationFixAchieved : Bool = false
var locationStatus : NSString = "Not Started"

var locationManager: CLLocationManager!

override func viewDidLoad() {
    super.viewDidLoad()
}

  func initLocationManager() {
   seenError = false
   locationFixAchieved = false
    locationManager = CLLocationManager()
   locationManager.delegate = self
   locationManager.locationServicesEnabled
   locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
}

  func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
    locationManager.stopUpdatingLocation()
    if (error) {
        if (seenError == false) {
            seenError = true
           print(error)
        }
    }
}

func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
    if (locationFixAchieved == false) {
        locationFixAchieved = true
        var locationArray = locations as NSArray
        var locationObj = locationArray.lastObject as CLLocation
        var coord = locationObj.coordinate

        println(coord.latitude)
        println(coord.longitude)
    }
}

 func locationManager(manager: CLLocationManager!,
    didChangeAuthorizationStatus status: CLAuthorizationStatus) {
        var shouldIAllow = false

        switch status {
        case CLAuthorizationStatus.Restricted:
            locationStatus = "Restricted Access to location"
        case CLAuthorizationStatus.Denied:
            locationStatus = "User denied access to location"
        case CLAuthorizationStatus.NotDetermined:
            locationStatus = "Status not determined"
        default:
            locationStatus = "Allowed to location Access"
            shouldIAllow = true
        }
        NSNotificationCenter.defaultCenter().postNotificationName("LabelHasbeenUpdated", object: nil)
        if (shouldIAllow == true) {
            NSLog("Location to Allowed")
            // Start location services
            locationManager.startUpdatingLocation()
        } else {
            NSLog("Denied access: \(locationStatus)")
        }
}
jayesh kavathiya
  • 3,531
  • 2
  • 22
  • 25
5

To get User Current Location :-

Step 1: let locationManager = CLLocationManager() // make object of CLLocationManager class.

Step 2: In viewDidLoad instantiate the CLLocationManager class like,

// For use in background

self.locationManager.requestAlwaysAuthorization()

// For use in foreground

self.locationManager.requestWhenInUseAuthorization()

if (CLLocationManager.locationServicesEnabled())
{
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}

Step 3: Now implement the delegate methods of CLLocationManager

  func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {

    var locValue:CLLocationCoordinate2D = manager.location.coordinate

    println("locations = \(locValue.latitude) \(locValue.longitude)")

  }

Step 4: Don't forget to add NSLocationAlwaysUsageDescription in the Info.plist as in iOS 8 it is mandatory to add this. This will ask permission to use user's location.

Mihir Oza
  • 2,768
  • 3
  • 35
  • 61
Programming Learner
  • 4,351
  • 3
  • 22
  • 34
3

I had the same issue. didUpdateLocations - was not working. Run your app. Go to the Settings page -> Privacy -> Location and turn off Location Services. didFailWithError will catch the error about absent Location Services. Then turn it on. Since that moment didUpdateLocations will catch locations.

salty
  • 61
  • 3
0

This is a bit of an old thread, yet none of the above worked for me on Swift 2.2 xCode 7.3.1.

The problem is I was using:

func locationManager(manager: CLLocationManager!, didUpdateLocation locations: [AnyObject]!) {
    print("Got location")
    locationManager.stopUpdatingLocation()
}

And this never got called. When I changed to:

func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("Got location")
    locationManager.stopUpdatingLocation()
}

It all worked out. Seems like the delegate is not called when using [AnyObject]