Plotting a users route taken on a map using MKPolyline

core-location, location, mapkit, mkpolyline, objective-c

Solution

You should just create a `NSMutableArray` to hold your locations that you instantiate in `viewDidLoad`. So have `didUpdateToLocation` (or, if supporting iOS 6 and higher, you should use `didUpdateToLocations`) simply add a location to an array, then build a `MKPolyline` from that array, add that `MKPolyline` to the map, and then remove the old `MKPolyline`. Or you could add all of the line segments as individual `MKPolyline` objects, but the idea is the same, create a model to hold you locations (e.g. a `NSMutableArray`) and then add the appropriate `MKPolyline` object(s) to the map view.

For example, you could do something like:

#pragma mark - CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    CLLocation *location = [locations lastObject];

    if (location.horizontalAccuracy < 0)
        return;

    [self.locations addObject:location];
    NSUInteger count = [self.locations count];

    if (count > 1) {
        CLLocationCoordinate2D coordinates[count];
        for (NSInteger i = 0; i < count; i++) {
            coordinates[i] = [(CLLocation *)self.locations[i] coordinate];
        }

        MKPolyline *oldPolyline = self.polyline;
        self.polyline = [MKPolyline polylineWithCoordinates:coordinates count:count];
        [self.mapView addOverlay:self.polyline];
        if (oldPolyline)
            [self.mapView removeOverlay:oldPolyline];
    }
}

And remember to specify how the map is to draw the `MKPolyline`. So set your view controller to be a the `delegate` of your `MKMapView`, and you can then do something like the following:

#pragma mark - MKMapViewDelegate

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolyline class]])
    {
        MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];

        renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        renderer.lineWidth   = 3;

        return renderer;
    }

    return nil;
}

// for iOS versions prior to 7; see `rendererForOverlay` for iOS7 and later

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
    if ([overlay isKindOfClass:[MKPolyline class]])
    {
        MKPolylineView *overlayView = [[MKPolylineView alloc] initWithPolyline:overlay];

        overlayView.strokeColor     = [[UIColor blueColor] colorWithAlphaComponent:0.7];
        overlayView.lineWidth       = 3;

        return overlayView;
    }

    return nil;
}

Problem

I'm quite new to Objective-c. In my app, I'm trying to plot the users taken route onto a map. Here is what I have so far that just gets the users current location: ``` #import "StartCycleViewController.h" #import "CrumbPath.h" @interface StartCycleViewController () @property (nonatomic, strong) CLLocationManager *locationManager; @property (nonatomic, strong) IBOutlet MKMapView *map; @property (nonatomic, strong) UIView *containerView; @end @implementation StartCycleViewController @synthesize cycleLocation = _cycleLocation; @synthesize currentCycleLocation = _currentCycleLocation; - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; [self startCycleLocation]; _containerView = [[UIView alloc] initWithFrame:self.view.bounds]; [self.view addSubview:self.containerView]; [self.containerView addSubview:self.map]; // Do any additional setup after loading the view. } - (void)dealloc { self.locationManager.delegate = nil; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - startCycleLocation - (void)startCycleLocation{ if (!_cycleLocation){ _cycleLocation = [[CLLocationManager alloc]init]; _cycleLocation.desiredAccuracy = kCLLocationAccuracyBestForNavigation; _cycleLocation.distanceFilter = 10; _cycleLocation.delegate = self; } [_cycleLocation startUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { NSLog(@"didUpdateToLocation: %@", newLocation); CLLocation *currentLocation = newLocation; if (currentLocation != nil) { self.longitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude]; self.latitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude]; } } - (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { NSLog(@"%@",error); if ( [error code] != kCLErrorLocationUnknown ){ [self stopLocationManager]; } } - (void) stopLocationManager { [self.cycleLocation stopUpdatingLocation]; } @end ``` I've had a look around online and gather that I should use `MKPolyline`and give it coordinates. But I'm just not sure how I would store the locations and then send them use `MKPolyline` to plot the points, continuously while the app is running.

Original source