I'm attempting to use implement an instance of MKMapView
, use CoreLocation
to track the users location, and then zoom in to where they are.
I only want to track the user's location when I'm in the foreground. Since my app is targeted for iOS8, I have a plist entry for the key NSLocationWhenInUseUsageDescription
.
When I run the app for the first time, the app appropriately asks if it can access my location. After I click 'Allow', I then receive the following warning from Xcode:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
...which is a bit confusing, as I am in fact calling requestWhenInUseAuthorization
, as can be seen in my code below:
@property (strong, nonatomic) IBOutlet MKMapView *mapView;
@property(nonatomic, retain) CLLocationManager *locationManager;
@end
@implementation MapView
- (void)viewDidLoad {
[super viewDidLoad];
[self locationManager];
[self updateLocation];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
self.locationManager = nil;
}
- (CLLocationManager *)locationManager {
//We only want to get the location when the app is in the foreground
[_locationManager requestWhenInUseAuthorization];
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
return _locationManager;
}
- (void)updateLocation {
_mapView.userTrackingMode = YES;
[self.locationManager startUpdatingLocation];
}
Does anyone have any insight into why this warning would be occurring?
You are calling
requestWhenInUseAuthorization
, that is true. But are you waiting until you get authorization? No, you are not. You (as the user) are tapping Allow, but that's happening too late: your code has already continued, going straight on to tell the map view to start tracking the user's location.Just look at the docs on
requestWhenInUseAuthorization
:Get that? Runs asynchronously. That means that asking for permission happens in the background on another thread.
And the docs go on to say:
So, implement that method. If you have just obtained permission, that is the signal that you can start using the location manager.
Also, you are missing an important step: you are not checking what the status actually is. You should only be asking for authorization if the status is undetermined. If the status is restricted or denied, you must not use the location manager at all; and if the status is granted, there is no point asking for authorization again.
So, just to sum up, your logical flowchart should be:
Check status.
Is the status Restricted or Denied? Stop. You cannot use get location updates or do location on a map.
Is the status Granted? Proceed to get location updates or do location on a map.
Is the status Undetermined? Request authorization and stop. Treat
locationManager:didChangeAuthorizationStatus:
as the completion handler for your authorization request. At that point, go back to start of the flowchart!