ovidiu.developer
ovidiu.developer

Reputation: 119

How to get CLLocationManager's current coordinate

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

Answers (1)

Paulw11
Paulw11

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

Related Questions