How do you store data from NSMutable Array in Core Data?

10,919

I've created a simple class that saves a polyline with an array when the app closes, and queries core data for all polylines when the app returns. I assume you know how to set up core data and managed object contexts. This pattern allows you to directly set and get NSArray objects into the core data object. The basic principle behind it is here: https://coderwall.com/p/mx_wmq

First, create the model with a transformable attribute (your array) and a data attribute to go with it.

model

Next, create a category on the polyline object.

category

You should now have these items in your file browser

files

Polyline+TransformableAttributes.h

#import "Polyline.h"

@interface Polyline (TransformableAttributes)

#pragma mark transformables

-(NSArray *)coordinates;
-(void)setCoordinates:(id)coordinates;

@end

Polyline+TransformableAttributes.m

@implementation Polyline (TransformableAttributes)

#pragma mark Transformables
-(NSArray *)coordinates {
    if (!self.coordinates_data)
        return nil;

    return [NSKeyedUnarchiver unarchiveObjectWithData:self.coordinates_data];
}

-(void)setCoordinates:(id)coordinates {
    NSData *coordinates_data = [NSKeyedArchiver archivedDataWithRootObject:coordinates];
    [self setValue:coordinates_data forKey:@"coordinates_data"];
}

@end

Appdelegate.m

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Polyline"];
    NSError *error;
    id results = [self.managedObjectContext executeFetchRequest:request error:&error];
    Polyline *polyline = (Polyline *)(results[0]);
    NSArray *coordinates = polyline.coordinates;

}

- (void)applicationWillResignActive:(UIApplication *)application
{
    NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"Polyline" inManagedObjectContext:self.managedObjectContext];
    Polyline *polyline = (Polyline *)object;
    [polyline setCoordinates:@[@"a", @"b", @"c"]];
    NSError *error;
    if ([self.managedObjectContext save:&error]) {
        NSLog(@"Saved");
    }
    else {
        NSLog(@"Error: %@", error);
    }
}

Please let me know if it works for you. I'll update my answer if needed, so that it can be useful. I can't remember where I originally found this pattern but it was a really helpful and highly upvoted

Edit 1: Added a gps view

Here is a new controller I added:

enter image description here

GPSViewController.h:

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "Polyline+TransformableAttributes.h"

@interface GPSViewController : UIViewController <CLLocationManagerDelegate>
{
    NSMutableArray *_locationsArray;
    Polyline *polyLine;
    CLLocationManager *locationManager;
}

-(IBAction)didClickStartGPS:(id)sender;
-(IBAction)didClickSaveCoordinates:(id)sender;
-(IBAction)didClickLoadCoordinates:(id)sender;

The code in my GPSViewController.m:

Initialize the array to store my coordinates.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    _locationsArray = [NSMutableArray array];
}

When you click the GPS button, it goes here. locationManager is an instance variable of the class.

-(IBAction)didClickStartGPS:(id)sender {
    locationManager = [[CLLocationManager alloc] init];
    [locationManager setDelegate:self];
    [locationManager startUpdatingLocation];
}

This saves the coordinates into a polyline and persists it. Note: with this code, I don't do any specific search descriptors, so if you click save multiple times, you'll get a bunch of polylines in your core data, and it'll probably only load the first one each time. You can do stuff like search through them for a certain id or date if you add that to the polyline object.

-(IBAction)didClickSaveCoordinates:(id)sender {
    /*
     NSInteger numberOfSteps = _locationsArray.count;
     // you don't need to convert it to a coordinates array.
     CLLocationCoordinate2D coordinates[numberOfSteps];
     for (NSInteger index = 0; index < numberOfSteps; index++) {
     CLLocation *location = [_locationsArray objectAtIndex:index];
     CLLocationCoordinate2D coordinate2 = location.coordinate;
     coordinates[index] = coordinate2;
     }
     */

    // get a reference to the appDelegate so you can access the global managedObjectContext
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;

    // creates a new polyline object when app goes into the background, and stores it into core data.
    if (!polyLine) {
        NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"Polyline" inManagedObjectContext:appDelegate.managedObjectContext];
        polyLine = (Polyline *)object;
    }

    [polyLine setCoordinates:_locationsArray];
    NSError *error;
    if ([appDelegate.managedObjectContext save:&error]) {
        NSLog(@"Saved");
    }
    else {
        NSLog(@"Error: %@", error);
    }
}

This loads the first polyline object from core data and converts it into your _locationArray of CLLocations. I don't do anything with the CLLocationCoordinate2D you can get from them.

-(IBAction)didClickLoadCoordinates:(id)sender {
    // get a reference to the appDelegate so you can access the global managedObjectContext
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;

    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Polyline"];
    NSError *error;
    id results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error];

    if ([results count]) {
        polyLine = (Polyline *)(results[0]);
        NSArray *coordinates = polyLine.coordinates;
        int ct = 0;
        for (CLLocation *loc in coordinates) {
            NSLog(@"location %d: %@", ct++, loc);
        }

        // this copies the array to your mutableArray
        _locationsArray = [coordinates mutableCopy];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    CLLocation *currentLocation = [locations lastObject];
    CLLocationDegrees latitude = currentLocation.coordinate.latitude;
    CLLocationDegrees longitude = currentLocation.coordinate.longitude;
    CLLocationCoordinate2D locationCoordinates = CLLocationCoordinate2DMake(latitude, longitude);

    //store latest location in stored track array;
    [_locationsArray addObject:currentLocation];
}

This code is updated on my github:

github.com/bobbyren/StackOverflowTest.git

Edit: To add a new MKPolyline for each Polyline:

NSArray *polylines = [fetchedResultsController allObjects];
for (Polyline *polyline in polylines) {
    MKPolyline *mkPolyline = [MKPolyline polylineWithCoordinates:polyline.coordinates count:ct]; // assuming you have written out how to return polyline.coordinates as a CLLocationCoordinate2D[]
    [mapView addOverlay:line];
}

[mapView reloadData];
Share:
10,919
Peeter Vedic
Author by

Peeter Vedic

Updated on June 04, 2022

Comments

  • Peeter Vedic
    Peeter Vedic almost 2 years

    The app i'm making draws a Polyline based on the users coordinates from CLLocationManager (these are all kept in an NSMutableArray)

    When the app closes, the current polyline disappears. How can I store the array of points in CoreData to be retrieved when the app starts up? All of the past 'routes' that the user has taken since initiating the app should be recovered and overlaid on the map (which may be quite a lot, so CoreData seems the best option from what i've gathered).

    This is the code I use to create an MKPolyline from the loaded coordinates

    -(IBAction)didClickLoadCoordinates:(id)sender {
    // get a reference to the appDelegate so you can access the global managedObjectContext
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Route"];
    NSError *error;
    id results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error];
    
    if ([results count]) {
        polyLine = (Route *)(results[0]);
        NSArray *coordinates = polyLine.coordinates;
        int ct = 0;
        for (CLLocation *loc in coordinates) {
            NSLog(@"location %d: %@", ct++, loc);
    
    
        }
    
    
        // this copies the array to your mutableArray
        _locationsArray = [coordinates mutableCopy];
    
    }
    
    NSInteger numberOfSteps = _locationsArray.count;
    
    //convert to coordinates array to construct the polyline
    
    CLLocationCoordinate2D clCoordinates[numberOfSteps];
    for (NSInteger index = 0; index < numberOfSteps; index++) {
        CLLocation *location = [_locationsArray objectAtIndex:index];
        CLLocationCoordinate2D coordinate2 = location.coordinate;
        clCoordinates[index] = coordinate2;
    }
    
    MKPolyline *routeLine = [MKPolyline polylineWithCoordinates:clCoordinates count:numberOfSteps];
    [_mapView addOverlay:routeLine];
    
  • Peeter Vedic
    Peeter Vedic over 9 years
    I'm a beginner so i'm currently reading up on Core Data and managing objects etc. Marked as answered for images and thorough detail - will read and implement soon. Thanks a lot!
  • mitrenegade
    mitrenegade over 9 years
    ok then i think for your case, try the simpler solution here: coderwall.com/p/mx_wmq. you basically convert your array into nsdata when you save core data, and unarchive it when you load it and need to access the array.
  • Peeter Vedic
    Peeter Vedic over 9 years
    I thought arrays couldn't be directly stored in core data? stackoverflow.com/questions/4546811/…
  • mitrenegade
    mitrenegade over 9 years
    in your core data object model, you can have an NSData attribute. That is essentially your array encoded into raw data bytes. Each time you save and load core data from the sql database, encode or decode it and set it to an array. My pattern gives you access to an NSArray attribute that doesn't get saved into the core data object, but is directly accessible as polyline.coordinateArray.
  • Peeter Vedic
    Peeter Vedic over 9 years
    I've implemented the Core Data framework into my project, i'm just wondering if I need to have a custom class that draws the polyline. In my app this is all done through methods in the ViewController... would you recommend creating a custom class? Thanks
  • mitrenegade
    mitrenegade over 9 years
    if you're talking about how to actually put the polyline into your view as a line and multiple dots? I'd probably look into MKMapView. Pull out the location points as CLLocationCoordinates and add annotations in the mapview. Maybe something like this: stackoverflow.com/questions/1336370/…
  • Peeter Vedic
    Peeter Vedic over 9 years
    I've used CLLocationManager to store the lat/long in an array already, which is then overlaid on the map with MKPolylineOverlay. What i'm asking is, do I need to create a custom class like you've done with Polyline.h and Polyline.m?
  • mitrenegade
    mitrenegade over 9 years
    If you're using core data, you have to create a core data model, which is the basic Polyline.h and Polyline.m. That's the object which gets stored into core data with an NSData attribute. You don't have to do the category, Polyline+TransformableAttributes.h and Poly+TransformableAttributes.m, which takes Polyline and adds methods to it to get and set an array. You can do this manually each time you save and load instead. Here's a decent read on categories: binpress.com/tutorial/objectivec-lesson-8-categories/73
  • Peeter Vedic
    Peeter Vedic over 9 years
    i'm having a lot of trouble here. I have my polyline implementation in my normal .h and .m files in the View Controller. I don't have a .h or .m file in my core data. If possible can you please send me your xcode project so I can figure out what i'm doing wrong here? I feel like i'm quite close @mitrenegade
  • mitrenegade
    mitrenegade over 9 years
    sure, i'll create a project you can use. core data is kind of tough to learn initially. meanwhile, did you create the Polyline.h and Polyline.m by selecting the Polyline entity in the core data model, and doing Editor->Create NSModel subclass? That's the way to generate a core data class which you don't edit.
  • mitrenegade
    mitrenegade over 9 years
    Go ahead and clone this repository: github.com/bobbyren/StackOverflowTest.git The relevant code for you is in the Core Data model, and applicationDidBecomeActive: and applicationWillResignActive:
  • Peeter Vedic
    Peeter Vedic over 9 years
    I figured out how to create the NSModel subclass, just not sure what goes in it and how it's different to the normal .h and .m in the ViewController. Thank you so much, i'll check out the code today!
  • mitrenegade
    mitrenegade over 9 years
    the difference is that creating a subclass from a core data entity means those files are dynamically generated. if you add a new attribute, say an integer called "type", you can regenerate the subclass and it will overwrite your .h and .m files. this is ideal, but any changes and custom methods you write will be overwritten unless you create a category, namely the Polyline+<categoryname>.h and .m files. those are useful to keep some handy methods around even if you change the polyline model and regenerate the subclasses.
  • mitrenegade
    mitrenegade over 9 years
    The handy methods created in Polyline+transformable category are used to change polyline coordinates from an array of CLLocations to an NSData that can be stored inside the core data object. Here's a nice read on the pattern of categories with core data: useyourloaf.com/blog/2010/03/23/…
  • Peeter Vedic
    Peeter Vedic over 9 years
    Learning a lot about subclasses and CoreData thanks to you! I have a question though - my NSMutableArray (with variable *locations) is created from CLLocationManager updates in the ViewController.h and .m files. Where do I implement the NSMutableArray into the example code that you've provided? Should I keep the NSArray or is that not required?
  • mitrenegade
    mitrenegade over 9 years
    the core data object is an immutable array...think of it as you're writing to something permanent when you want to write it to disk. while you're aggregating the locations, just do it in a mutable array owned by the ViewController. There should only be one instance when you save those coordinates into core data. That is probably when you close the app, or you click a button that says "save coordinates" or some single moment. At that moment, you can create a polyline object, copy over the coords from the mutable array into the NSArray, and save to core data.
  • Peeter Vedic
    Peeter Vedic over 9 years
    Ok that makes more sense. Right now I have the mutable array of constantly updating locations (declared in ViewController), and this is then used to make a MKPolyline in the ViewController. I'm just confused about where and how I should create the polyline object.
  • mitrenegade
    mitrenegade over 9 years
    here's the question you should ask. do you need core data? because you want to persist the coordinates when you close the app, the answer is probably yes. here are reasons you'd use core data. stackoverflow.com/questions/1883879/… now, for the second to second operation of your app, do you need core data? probably not, since you're fine storing coordinates into an array. only when you need to persist it to disk, will you need the core data interface. you will translate the coords in mkpolyline to a polyline when you exit the app, for one.
  • mitrenegade
    mitrenegade over 9 years
    the way i use core data in some of my objects has to do with web APIs. i talk with a backend that sends me down a bunch of json objects. these are stored into core data, for example, student = [{name: Peeter, city: new york}, {name: bobby, city: san francisco}] gets parsed into two Student objects. I don't need them until later, when I open a tableview and load the students in. at that point, I pull the objects from core data. otherwise, they're just stored in the database.
  • Peeter Vedic
    Peeter Vedic over 9 years
    Okay so I get that CoreData can be accessed by declaring the ManagedObjectContext in the AppDelegate. But should I tell it to store a polyline OBJECT with the coordinates from my NSMutableArray in Viewcontroller.m? I'm just not seeing how those two are linked
  • mitrenegade
    mitrenegade over 9 years
    @PeeterVedic this whole discussion stems from you needing to store the coordinates in an array and persisting them. you don't have to store the data into an object representation in core data. maybe core data is a little beyond your needs. here's another way to persist an array: use NSUserDefaults: stackoverflow.com/questions/7570708/…
  • mitrenegade
    mitrenegade over 9 years
    the polyline object is an abstraction that changes your array of cllocation coordinates into a core data object. there's no way to persist an mkpolyline directly because it is not NSCoding compliant. so yes, you have to teoo the managedObjectContext to create a polyline object, populate the polyline data with your array or coordinates, and save it to the database.
  • Peeter Vedic
    Peeter Vedic over 9 years
    I think CoreData is going to be initially the toughest to grasp, but for the app i'm developing a ton of location coordinates need to be stored and then retrieved when the app starts. I really appreciate you taking the time to help me through this - i've also been watching tutorials and slowly grasping the abstract idea that is CoreData. My biggest question is still, how do you populate the polyline data with my NSMutableArray that has been created? Can you give me a direct example?
  • Peeter Vedic
    Peeter Vedic over 9 years
    So to be clear, i've already got CLLocation constantly updating locations that are being stored in NSMutableArray *locationsArray. I'd just like to know how to use this array to populate the data to be saved to the database.
  • mitrenegade
    mitrenegade over 9 years
    take a look at the sample code i sent you. that code currently populates a Polyline core data object when the app closes. It basically takes your array and converts it into data that can be persisted. The line is just this: [polyline setCoordinates:@[@"a", @"b", @"c"]]; For a set of coordinates, it would be [polyLine setCoordinates:yourCLLocationArray];. It's actually so simple that it's easy to miss. try it, and let me know if it works.
  • mitrenegade
    mitrenegade over 9 years
    all of the bulk code is in the Polyline+Transformable.m file, if you want to dig into it. It takes your NSMutableArray, encodes it into an NSData object, and stores the NSData into the core data model. When you open the app, it takes whatever NSData is stored, converts it back into an NSArray, and sets it to the Polyline.m attribute. At that point you would want to pull out each coordinate from polyLine and put it into your NSMutableArray for display.
  • Peeter Vedic
    Peeter Vedic over 9 years
    This is all probably simple but it's very frustrating for me. So just two basic questions: 1) In the example you do all the CLLocation stuff in the AppDelegate.m file. Should I be using my code in the AppDelegate file too? This is my code in the ViewController.m file to get the CLLocations into my NSMutableArray...
  • Peeter Vedic
    Peeter Vedic over 9 years
    I've followed exactly however in the AppDelegate.h declaration of Polyline *polyLine it's displaying error saying "unknown type". In your code it's obviously an NSManagedObject, any clues why it's not recognising it?
  • mitrenegade
    mitrenegade over 9 years
    did you generate Polyline.m and Polyline.h by selecting on the Model.xcdatamodeld file and going to Editor->Create NSManagedObject Subclass, or did you create Polyline.m and Polyline.h by hand? Does your Polyline.h subclass NSManagedObject this way? #import <CoreData/CoreData.h> @interface Polyline : NSManagedObject?
  • Peeter Vedic
    Peeter Vedic over 9 years
    Yep did all that. To fix the problem I changed all instances of Polyline to Route - Xcode kept trying to tell me it was an MKPolyline object and after changing it to Route it fixed the error! I now have a working, save load implementation of CoreData thanks to you! Next step now is to form a new polyline overlay with the loaded points, but i'll have a careful run through of what i've currently learnt before doing that. You have taught me so much, thanks!
  • Peeter Vedic
    Peeter Vedic over 9 years
    So the polyline overlay I had in my previous code is now gone. It should be easy to get back with this MKPolyline * routeLine = [MKPolyline polylineWithCoordinates: but it's not letting me give it the locationsArray. What code should I use to construct the polyline?
  • Peeter Vedic
    Peeter Vedic over 9 years
    Ok I needed to convert the locationsArray to a coordinates array, to get the CLLocationCoordinate 2D object. It's now displaying the polyline.
  • Peeter Vedic
    Peeter Vedic over 9 years
    One final question, your code works perfectly and as you said, it only loads the polyline from the first time that I pressed saved. How would one go about loading all previous points, from all previous saves?
  • mitrenegade
    mitrenegade over 9 years
    peeter it sounds like you're making a lot of progress! i'm glad it all worked out. stackoverflow got mad at me for making this long comment thread but wouldn't let me take it to a chat because you're too low in points haha. to load all polylines, look into nsfetchedrequest. this one: id results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error]; fetches all core data objects based on your request. you can also add nssortdescriptors and nspredicates. i would add an attribute to polyline called "date" and each time you create a polyline, set it to the current date.
  • Peeter Vedic
    Peeter Vedic over 9 years
    I can only hope this conversation will be as incredibly helpful to others as it was to me! Haha need 14 more rep - I only started app development 3 weeks ago but it shouldn't take me too much longer - my brain is about to explode with new knowledge... Anyway sorry stack overflow and i'll check out the fetching. Thank you once again
  • Peeter Vedic
    Peeter Vedic over 9 years
    I looked up fetch request and the code implemented currently seems to be a 'basic fetch', which is all i'm really after. In this case a date attribute would be overkill because it doesn't matter how polylines are sorted, I just need all polylines to be retrieved. I don't really understand why the code you've given doesn't retrieve all (how did you know it would only retrieve the first save?) Spent all day trying to figure this one out :S
  • mitrenegade
    mitrenegade over 9 years
    oh, all i meant was that I'm only pulling out the first object from the fetched results: polyLine = (Polyline *)(results[0]); I use that object to display the coordinates. In the code I give you, each time you save a new polyline object that contains your coordinates. so it was a warning that there will be multiple polyline coordinates inside core data, each one contains all of your CLLocationCoordinates. if you pull the first one as I did, it might not be your most recent one.
  • Peeter Vedic
    Peeter Vedic over 9 years
    Okay gotcha. But what code should I use to pull all objects? I tried replacing 0 with different numbers in the results[0] bit, and it recalled the separate polylines from different saves (as you said). But I want to just pull all previous polylines without any kind of sorting. Basically results [all] but that obviously doesn't work because objective c is too much fun. Anyway this is probably the simplest thing ever so please forgive my utter ignorance
  • mitrenegade
    mitrenegade over 9 years
    results is an NSArray. Basically, id results = [appDelegate.managedObjectContext executeFetchRequest:request error:&error]; gives you the array of all polylines, and you can just do a for loop through them. id is the equivalent of (void *) and is typically used as an unknown type, but if you look at the executeFetchRequest: signature, it returns an NSArray. So if you wish, you can loop through all the polylines and look for the one you last saved, using perhaps an additional date parameter as I suggested before.
  • Peeter Vedic
    Peeter Vedic over 9 years
    But I don't want just the last saved, or just the first saved. I want to display all saved polylines. Is there any way to do this?
  • mitrenegade
    mitrenegade over 9 years
    peeter, the way polyline.m is implemented, each Polyline object is a container for all of your cllocation points. each time you click the save button in my sample app, it creates one polyline, stores the whole array of CLLocationCoordinates into it, and sets that object into core data. so each time you use it, you're saving 10 coordinates, for example. if you want all of the saved polyline objects, just use the array "result." what i'm warning you about is that if you get a new coordinate and click save, it'll create a new polyline that contains all of the coordinates.
  • mitrenegade
    mitrenegade over 9 years
    then, when you pull out the fetched list of polylines, there will be a polyline with your 10 coordinates, there will be a polyline with 11 coordinates, etc. does that make any sense at all? do you understand the concept of an array? I've clearly shown you that result is an array, result[0] is the first object in the array, and if you want all the polylines, just use all the objects in result: for(int i=0; i<result.count; i++) { NSLog(@"%@", result[i]); }
  • mitrenegade
    mitrenegade over 9 years
    and if you actually put some break points into the implementation of polyline.m, you'll see that your coordinates are an array that are being saved into a polyline object, and being converted into an NSData. I don't have the time to implement the whole app for you so I've given you an example of how to dump a Polyline to memory. You don't need every polyline. You only need one polyline, which is used to store all of your CLLocation points. Figure out some way of creating a polyline and storing it into coredata, while making certain that the one you pull out again is the same one.
  • mitrenegade
    mitrenegade over 9 years
    for example, if you add a Date attribute as I suggest, you can create a new polyline each time you want to save your coordinates. then when you retrieve all polylines that are stored in memory, pull out the most recently stored polyline, so that its array contains the most updated array of CLLocation coordinates.
  • mitrenegade
    mitrenegade over 9 years
    alternatively, each time you save a polyline, load all polylines from core data first. If one already exists, just update its coordinates. That way you'll always only have one Polyline object in core data, which will contain 10 points, 11 points, 12 points, etc each time as you update your coordinates.
  • mitrenegade
    mitrenegade over 9 years
    if you actually want multiple polylines, for example if you have three maps that you want to save separately, add something like a "name" attribute. For each map, save its coordinates and its name into a polyline object. You can add a NSPredicate to search for a specific query: NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", mapName]; and it will pull out the core data with name = mapName.
  • Peeter Vedic
    Peeter Vedic over 9 years
    Thank you for your patience and thorough explanation, that made everything much clearer. I will try implement a date attribute to the polyline object and pull only the most recently updated polyline (I don't need all polylines, just the most updated). Thanks again and I will not pester you anymore, you've done more than enough. p.s when I finish the app your name is most definitely going in the credits :D
  • mitrenegade
    mitrenegade over 9 years
    haha, good luck! and please do ask me if anything gets you really really stuck.
  • Peeter Vedic
    Peeter Vedic over 9 years
    Hey, me again. I've run into a strange issue that is probably easily resolvable. I load the coordinates from core data when the app starts, thereby creating a polyline of the past route on the screen (all good) - but when I start updating locations, it connects the two polylines from the last location on the loaded polyline to the first cllocation update. So where the lines should be separate, there's a large straight bit of polyline. Is there a way to filter out this result? I've tried using a NSDate object to look at the timestamp but not working..
  • Peeter Vedic
    Peeter Vedic over 9 years
  • mitrenegade
    mitrenegade over 9 years
    i think you'll have to have multiple polylines, and add multiple overlays to the map.
  • mitrenegade
    mitrenegade over 9 years
    to be more clear, so for each polyline object, make a different MKPolyline object from it, and do [mapview addOVerlay:mkPolyline]. it also depends on how you're drawing your polylines. you can add a breakpoint in the mapview rendering you can maybe see what's causing the drawing between the last point and the new point.
  • Peeter Vedic
    Peeter Vedic over 9 years
    For my app it would be best to load all polylines, and then update that. There are going to be separate polylines, or in other words, gaps between polylines correlating with the apps closure. How would you recommend creating and saving the separate polylines? Is there a way to specify in the CLLocationManager to say "if points already exist (polylines loaded), then discard their locations and update from current location? To prevent this kind of thing from happening (straight jump to current location from last point) i.imgur.com/WM51qAe.png
  • mitrenegade
    mitrenegade over 9 years
    look at the polyline object as a way to store coordinates, and maybe group them. otherwise, any logic you need to have should be done somewhere in your controller. my understanding is that you'll track a set of locations, like where a person's gone while the app's open. when you close it, store those coordinates as one polyline, add a timestamp or something else, and save it to core data. next time your app opens, load any polylines that you've stored, and then your app should do the logic of deciding whether to connect one to the other, or draw them separately.
  • mitrenegade
    mitrenegade over 9 years
    each polyline is just an NSArray of coordinates. so if you don't want them to be connected to each other, create a new MKPolyline from each NSArray of coordinates, and add that overlay to the map. Each MKMapView can have multiple MKPolyline overlays, and they won't connect to each other. Are you pulling out all the CLLocationCoordinates and putting them into the same array? If you do that they will be connected. let me know if this is what you're doing.
  • Peeter Vedic
    Peeter Vedic over 9 years
    All the CLLocationCoordinates are going into the same array. This array forms the polyline. So when I open the app again, the polyline loads, and I need to draw the newly updated polyline separately... In no way should they be connected because the user will always be in a new location. So should I do multiple overlays? How can I do this?
  • mitrenegade
    mitrenegade over 9 years
    yes, you should make multiple arrays, and multiple overlays. it's actually quite simple. for each polyline object, create a different array of CLLocationCoordate2D values, then: MKPolyline *polyline = [MKPolyline polylineWithCoordinates:fieldCoordinates count:fieldCoordinateCount]; [mapView addOverlay:polyline];
  • mitrenegade
    mitrenegade over 9 years
    and i've seen some comments where you should use a mapview renderer which gives you control over each line, if you're not already doing that. here's code i used: -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay { if ([overlay isKindOfClass:[MKPolyline class]]) { MKPolyline *polyline = (MKPolyline *)overlay; MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay]; renderer.lineWidth = 4; renderer.strokeColor = [UIColor grayColor]; renderer.lineCap = kCGLineCapRound; return renderer;}return nil;}
  • Peeter Vedic
    Peeter Vedic over 9 years
    how do I create a different array of CLLocationCoordinate2D values for each line? I understand everything else basically, i'm using the MKOverlayRenderer that you suggested :) Thanks!
  • mitrenegade
    mitrenegade over 9 years
    I've edited my answer...it seems like it should be really simple, so maybe you can update your post with the code where you load the Polylines from core data, turn them into a single CLLocation2D array, and draw one single MKPolyline from them. That way we can figure out how you can easily separate each.
  • Peeter Vedic
    Peeter Vedic over 9 years
    Updated my post - all the loaded points are copied into the locations array and drawn from that. That can't be right... Where does the code you've provided go. In viewDidLoad?
  • Greg
    Greg about 8 years
    struggling to translate this to swift - have raised a question here stackoverflow.com/questions/36761841/…
  • mitrenegade
    mitrenegade about 8 years
    oooh...i actually havent translated much of my core data over to swift so i cant answer that question right now. i started using some extensions but nothing with transformables yet. i'll look into it when i get a chance.