Reputation: 119
I have a UIViewController where I want to display a map centered on current position.
AppDelegate's didFinishLaunchingWithOptions method looks like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.locationManager = [[CLLocationManager alloc] init];
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
return YES;
}
My UIViewController.m class looks like this:
@interface GMapViewController ()<CLLocationManagerDelegate>
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@property (strong, nonatomic) CLLocation *currentLocation;
@end
@implementation GMapViewController
#pragma mark - Lifecycle methods
- (void)viewDidLoad {
[super viewDidLoad];
self.currentLocation = [CLLocation new];
[[[AppDelegate appDelegate] locationManager] setDelegate:self];
MKCoordinateRegion visibleRegion;
visibleRegion.center = self.currentLocation.coordinate;
visibleRegion.span = MKCoordinateSpanMake(200, 200);
[self.mapView setRegion:visibleRegion animated:YES];
}
#pragma mark - CLLocationManagerDelegate's methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
self.currentLocation = [locations lastObject];
}
The thing is the CLLocationManager's didUpdateLocations delegate method is called too late as the currentLocation property has no value when the viewDidLoad is called.
How can I get the current coordinate before viewDidLoad being called ?
Upvotes: 0
Views: 77
Reputation: 114992
You need to refresh your map view once the location has been updated; this will take some time.
You also have a potential race condition, because you call startUpdatingLocation
in your AppDelegate, but the view controller isn't set as the delegate until viewDidLoad
. The delegate will almost certainly be set before the location is updated, but you can't guarantee this.
I would suggest that you move everything into your view controller and if you only want to update the map once, use requestLocation
:
@interface GMapViewController ()<CLLocationManagerDelegate>
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@property (strong, nonatomic) CLLocation *currentLocation;
@property (strong, nonatomic) CLLocationManager *locationManager;
@end
@implementation GMapViewController
#pragma mark - Lifecycle methods
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.currentLocation = nil;
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
[self.locationManager requestAlwaysAuthorization];
} else {
[self.locationManager requestLocation];
}
-(void) setMapTo:(CLLocation *)location {
MKCoordinateRegion visibleRegion;
visibleRegion.center =location.coordinate;
visibleRegion.span = MKCoordinateSpanMake(200, 200);
[self.mapView setRegion:visibleRegion animated:YES];
}
#pragma mark - CLLocationManagerDelegate's methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *currentLocation = [locations lastObject];
dispatch_async(dispatch_get_main_queue(), ^{
[self setMapTo:currentLocation];
});
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status != kCLAuthorizationStatusRestricted && status != kCLAuthorizationStatusDenied) {
[manager requestLocation];
}
}
If you just want the map to track the user's location continually then you can simply set the map view's userTrackingMode
property to MKUserTrackingModeFollow
Upvotes: 1