How to store and recall MKMapPoint using Core Data
===

I have been modifying the [Breadcrumb][1] sample code provided by Apple and am attempting to incorporate a Core Data model to allow the storage of the MKOverlay properties.  The steps I have taken so far include:

 1. Creating an entity for a Layer in Core Data which includes properties for each of those used in the Breadcrumb example (see Layer.h below for the NSManagedObject subclass)
 2. Created a category for the Layer class which conforms to the <MKOverlay> overlay protocol and contains the methods from the Breadcrumb sample code

In my attempts to resolve some of the conversion issues related to the MKMapPoint and pthread properties, bridges have been inserted (based on Xcode suggestions) and other modifications made.  The main issue I seem to be facing at this point is related to setting the points property, which throws this error when tempLayer.points = pointText is called:

>CoreData: error: Property 'setPoints:' is a scalar type on class 'Layer' that does not >match its Entity's property's scalar type.  Dynamically generated accessors do not support >implicit type coercion.  Cannot generate a setter method for it.

Since I am not familiar with C structs and their relation to Core Data, I need help determining the best approach for saving the MKMapPoints property to Core Data so I can retrieve them and add to the map as an overlay.


Layer.h
    
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
    #import <MapKit/MapKit.h>
    #import <pthread.h>
    
    @class Drawing;
    
    @interface Layer : NSManagedObject {
        pthread_rwlock_t rwLock;
        MKMapPoint *points;
        NSUInteger pointCount;
        NSUInteger pointSpace;
        
        MKMapRect boundingMapRect;
    
    }
    
    @property (nonatomic) MKMapRect boundingMapRect;
    @property (nonatomic, retain) NSDate * createdDate;
    @property (nonatomic, retain) NSNumber * lineAlpha;
    @property (nonatomic, retain) UIColor * lineColor;
    @property (nonatomic, retain) NSNumber * lineWidth;
    @property (nonatomic, retain) NSNumber * pointCount;
    @property (nonatomic) MKMapPoint * points;
    @property (nonatomic, retain) NSNumber * pointSpace;
    @property (nonatomic) pthread_rwlock_t rwLock;
    @property (nonatomic, retain) Drawing *drawing;
    
    @end

Layer.m
    
    #import "Layer.h"
    
    @implementation Layer
    
    @dynamic boundingMapRect;
    @dynamic createdDate;
    @dynamic lineAlpha;
    @dynamic lineColor;
    @dynamic lineWidth;
    @dynamic pointCount;
    @dynamic points;
    @dynamic pointSpace;
    @dynamic rwLock;
    @dynamic drawing;
    
    @end

Layer+Create.h

    #import <MapKit/MapKit.h>
    #import <pthread.h>
    
    #import "Layer.h"
    
    @interface Layer (Create) <MKOverlay>
    
    // Initialize the Layer with the starting coordinate.
    // The Layer's boundingMapRect will be set to a sufficiently large square
    // centered on the starting coordinate.
    //
    - (id)initWithCenterCoordinate:(CLLocationCoordinate2D)coord inManagedObjectContext:(NSManagedObjectContext *)context;
    
    // Add a location observation. A MKMapRect containing the newly added point
    // and the previously added point is returned so that the view can be updated
    // in that rectangle.  If the added coordinate has not moved far enough from
    // the previously added coordinate it will not be added to the list and
    // MKMapRectNull will be returned.
    //
    - (MKMapRect)addCoordinate:(CLLocationCoordinate2D)coord;
    
    - (void)lockForReading;
    
    // The following properties must only be accessed when holding the read lock
    // via lockForReading.  Once you're done accessing the points, release the
    // read lock with unlockForReading.
    
    - (void)unlockForReading;
    
    @end

Layer+Create.m

    #import "Layer+Create.h"
    
    #define INITIAL_POINT_SPACE 1000
    
    // Minimum change in distance between two coordinates that will be captured in the layer
    #define MINIMUM_DELTA_METERS_ADD_COORDINATE 1.0
    #define MINIMUM_DELTA_METERS_CLOSE_SHAPE 3.0
    
    @implementation Layer (Create)
    
    - (id)initWithCenterCoordinate:(CLLocationCoordinate2D)coord inManagedObjectContext:(NSManagedObjectContext *)context
    {
        //self = [super init];
        //if (self)
    	//{
        Layer *tempLayer = [NSEntityDescription insertNewObjectForEntityForName:@"Layer" inManagedObjectContext:context];
        
        // initialize point storage and place this first coordinate in it
        tempLayer.pointSpace = [NSNumber numberWithInt:INITIAL_POINT_SPACE];
        MKMapPoint * pointTest = malloc(sizeof(MKMapPoint) * [tempLayer.pointSpace longValue]);
        pointTest[0] = MKMapPointForCoordinate(coord);
        tempLayer.points = pointTest;
        tempLayer.pointCount = [NSNumber numberWithInt:1];
        
        // bite off up to 1/4 of the world to draw into.
        MKMapPoint origin = MKMapPointForCoordinate(coord);
        origin.x -= MKMapSizeWorld.width / 8.0;
        origin.y -= MKMapSizeWorld.height / 8.0;
        MKMapSize size = MKMapSizeWorld;
        size.width /= 4.0;
        size.height /= 4.0;
        tempLayer.boundingMapRect = (MKMapRect) { origin, size };
        MKMapRect worldRect = MKMapRectMake(0, 0, MKMapSizeWorld.width, MKMapSizeWorld.height);
        tempLayer.boundingMapRect = MKMapRectIntersection(tempLayer.boundingMapRect, worldRect);
        
        // initialize read-write lock for drawing and updates
        pthread_rwlock_init(&rwLock, NULL);
        //}
        return tempLayer;
    }
    
    - (void)dealloc
    {
        free(self.points);
        pthread_rwlock_destroy((__bridge pthread_rwlock_t *)([self valueForKey:@"rwLock"]));
    }
    
    - (CLLocationCoordinate2D)coordinate
    {
        return MKCoordinateForMapPoint(self.points[0]);
    }
    
    - (MKMapRect)boundingMapRect
    {
        return self.boundingMapRect;
    }
    
    - (void)lockForReading
    {
        pthread_rwlock_rdlock((__bridge pthread_rwlock_t *)([self valueForKey:@"rwLock"]));
    }
    
    - (void)unlockForReading
    {
        pthread_rwlock_unlock((__bridge pthread_rwlock_t *)([self valueForKey:@"rwLock"]));
    }
    
    
    - (MKMapRect)addCoordinate:(CLLocationCoordinate2D)coord
    {
        
        // Acquire the write lock because we are going to be changing the list of points
        pthread_rwlock_wrlock((__bridge pthread_rwlock_t *)([self valueForKey:@"rwLock"]));
        
        // Convert a CLLocationCoordinate2D to an MKMapPoint
        MKMapPoint newPoint = MKMapPointForCoordinate(coord);
        MKMapPoint prevPoint = newPoint;
        if (self.pointCount > 0) {
            prevPoint = self.points[[self.pointCount intValue] - 1];
        }
        
        // Get the distance between this new point and the previous point.
        CLLocationDistance metersApartAddCoord = MKMetersBetweenMapPoints(newPoint, prevPoint);
        MKMapRect updateRect = MKMapRectNull;
        
        if (metersApartAddCoord > MINIMUM_DELTA_METERS_ADD_COORDINATE)
        {
            // Grow the points array if necessary
            if (self.pointSpace == self.pointCount)
            {
                self.pointSpace = [NSNumber numberWithInt:[self.pointSpace intValue] * 2];
                self.points = realloc(self.points, sizeof(MKMapPoint) * [self.pointSpace longValue]);
            }
            
            // Add the new point to the points array
            self.points[[self.pointCount intValue]] = newPoint;
            self.pointCount = [NSNumber numberWithInt:[self.pointCount integerValue] + 1];
            
            // Compute MKMapRect bounding prevPoint and newPoint
            double minX = MIN(newPoint.x, prevPoint.x);
            double minY = MIN(newPoint.y, prevPoint.y);
            double maxX = MAX(newPoint.x, prevPoint.x);
            double maxY = MAX(newPoint.y, prevPoint.y);
            
            updateRect = MKMapRectMake(minX, minY, maxX - minX, maxY - minY);
        }
        
        // Get the distance between this new point and the starting point
        // If within threshold, prompt user to close circle
        CLLocationDistance metersApartCloseShape = MKMetersBetweenMapPoints(newPoint, self.points[0]);
        
        pthread_rwlock_unlock((__bridge pthread_rwlock_t *)([self valueForKey:@"rwLock"]));
        
        return updateRect;
    }
    
    
    @end


  [1]: http://developer.apple.com/library/ios/#samplecode/Breadcrumb/Introduction/Intro.html