Search code examples
iosobjective-ccllocationmanagermkoverlay

Getting Location Updates in Multiple View Controllers


Imagine the BreadCrumb demo which is an app for tracking the users travel path, with the necessary updates for iOS 7. https://developer.apple.com/library/ios/samplecode/Breadcrumb/Introduction/Intro.html

But now, I am trying to have a second View Controller (TrackOnMapViewController) that has a MapView in it and I can navigate (through a push segue, let say) to TrackOnMapViewController from the first one that BreadCrumb shows the user's path on its own MapView. I know it doesn't make sense to have a second view that shows the same thing as the first view, but that's not the point of my question anyway. So right now, the first View Controller implements

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

and in it updates the Overlay on the MapView of the first View Controller.

I implemented the Segue as follows:

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString: @"showMap"])
    {
        TrackOnMapViewController *tomvc = (TrackOnMapViewController *)segue.destinationViewController;
        tomvc.crumbs = self.crumbs;
    }
}

Therefore once I segue to TrackOnMapViewController, in the ViewDidLoad I have

- (void)viewDidLoad
{
    [super viewDidLoad];

    if (self.crumbs)
    {

        [self updatePathTravelled:self.crumbs];

        [self.mapView addOverlay:self.crumbs];
        MKCoordinateRegion region =
        MKCoordinateRegionMakeWithDistance(MKCoordinateForMapPoint(self.crumbs.points[0]), 400, 400);
        [self.mapView setRegion:region animated:YES];
    }
}

And also I implemented:

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
    if (!self.crumbView)
    {
        _crumbView = [[CrumbPathView alloc] initWithOverlay:overlay];
    }
    return self.crumbView;
}

in TrackOnMapViewController.

So the app works fine in the sense that in the first view controller the user's path is tracked on the MapView and when I segue to TrackOnMapViewController I see the path, but the problem is the path won't get updated in TrackOnMapViewController (which I understand, because there is no code to update the path). So my question is, what is the best way to update the path in TrackOnMapViewController. I can't imagine that the answer would be to implement

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

in the second view controller as well. I imagine I should somehow do this update whenever the first view controller does the location update. Or maybe move the location update to somewhere else altogether and use the updates in multiple view controllers. But I am not sure how to do these, if they are correct ways at all. A detailed answer would be appreciated. Thanks!


Solution

  • Well, I ended up using NSNotificationCenter as follows. I like this solution slightly better than what Mike suggested in his comment, i.e., using Singleton.

    So in the original ViewController I added

    NSDictionary* userInfo = @{@"Crumbs": self.crumbs};
    [[NSNotificationCenter defaultCenter] postNotificationName:@"CrumbPathGotUpdated" object:self userInfo: userInfo];
    

    Right after self.crumbs has an updated value. And in TrackOnMapViewController, in ViewdidLoad I added

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(CrumbPathUpdated:) name:@"CrumbPathGotUpdated" object:nil];
    

    and the method

    - (void) CrumbPathUpdated:(NSNotification *) notification
    {
        NSDictionary* userInfo = notification.userInfo;
        CrumbPath *crumbs = (CrumbPath *)userInfo[@"Crumbs"];
        [self updatePathTravelled:crumbs];
    }