How to use MKMapView's "Shows User Location" in iOS8?

Kuba Suder picture Kuba Suder · Dec 1, 2014 · Viewed 10.4k times · Source

When you add an MKMapView component to the view in Interface Builder, there are checkboxes that let you configure what it shows:

enter image description here

When you check "User Location", it automatically shows user's location on the map.

However, since iOS 8 you're supposed to ask for location permission before showing user's location. If you don't, you get a "Trying to start MapKit location updates without prompting" warning in the console.

So I've added a NSLocationWhenInUseUsageDescription key to the plist, and added this code to viewDidLoad:

if CLLocationManager.authorizationStatus() == .NotDetermined {
    CLLocationManager().requestWhenInUseAuthorization()
}

This doesn't seem to work though. I do get a popup asking for permission, but before I select an answer, it hides by itself, the map loads below it and I get the warning in the console.

I know I can set the showsUserLocation property in the code instead, only after getting the permission; but my point is, there is this checkbox in IB that is supposed to do the same thing, except it starts the tracking immediately. Does that mean that we're not supposed to use this checkbox at all since iOS 8? Or am I using it incorrectly?

--

Update: actually, the popup hides by itself regardless if "shows user location" is set or not. I've tried doing it in viewWillAppear or viewDidAppear instead, but that didn't help. So I'm not sure where exactly am I supposed to call requestwhenInUseAuthorization when using an MKMapView...

Answer

TonyMkenu picture TonyMkenu · Dec 2, 2014

Your CLLocationManager instance is released by ARC after the method completed executing. As soon as the instance was released, the dialog disappeared. The solution was rather simple. Change the CLLocationManager instance from being a method-level variable to be a class-level instance variable, and make it Strong - this is for ObjC :)

For Swift... do something like that:

    class YourViewController: UIViewController,CLLocationManagerDelegate {
    ...
    let locationManager = CLLocationManager()


    override func viewDidLoad() {
            super.viewDidLoad()
            // Ask for permission for location
            locationManager.delegate = self

            if(locationManager.respondsToSelector("requestAlwaysAuthorization")) {
                locationManager.requestAlwaysAuthorization()
                //or
                //locationManager.requestWhenInUseAuthorization()
            }
    ...
    }

so... don't use CLLocationManager().requestWhenInUseAuthorization() - instead use locationManager.requestWhenInUseAuthorization() - locationManager declared early