#import "Path.h" static void saveApplier(void* info, const CGPathElement* element) { NSMutableArray* a = (NSMutableArray*) info; int nPoints; switch (element->type) { case kCGPathElementMoveToPoint: nPoints = 1; break; case kCGPathElementAddLineToPoint: nPoints = 1; break; case kCGPathElementAddQuadCurveToPoint: nPoints = 2; break; case kCGPathElementAddCurveToPoint: nPoints = 3; break; case kCGPathElementCloseSubpath: nPoints = 0; break; default: [a replaceObjectAtIndex:0 withObject:[NSNumber numberWithBool:NO]]; return; } NSNumber* type = [NSNumber numberWithInt:element->type]; NSData* points = [NSData dataWithBytes:element->points length:nPoints*sizeof(CGPoint)]; [a addObject:[NSDictionary dictionaryWithObjectsAndKeys:type,@"type",points,@"points",nil]]; } @implementation Path - (CGPathRef)path { return path; } - (void)setPath:(CGPathRef)newPath { if (path != newPath) { CGPathRelease(path); path = CGPathRetain(newPath); } } - (BOOL)saveToFile:(NSString*)fileName { // Convert path to an array NSMutableArray* a = [NSMutableArray arrayWithObject:[NSNumber numberWithBool:YES]]; CGPathApply(path, a, saveApplier); if (![[a objectAtIndex:0] boolValue]) { return NO; } // Write path return [a writeToFile:fileName atomically:YES]; } - (BOOL)loadFromFile:(NSString*)fileName { // Read path NSArray* a = [NSArray arrayWithContentsOfFile:fileName]; if (!a) return NO; // Recreate (and store) path CGMutablePathRef p = CGPathCreateMutable(); for (NSInteger i = 1, l = [a count]; i < l; i++) { NSDictionary* d = [a objectAtIndex:i]; CGPoint* points = (CGPoint*) [[d objectForKey:@"points"] bytes]; switch ([[d objectForKey:@"type"] intValue]) { case kCGPathElementMoveToPoint: CGPathMoveToPoint(p, NULL, points[0].x, points[0].y); break; case kCGPathElementAddLineToPoint: CGPathAddLineToPoint(p, NULL, points[0].x, points[0].y); break; case kCGPathElementAddQuadCurveToPoint: CGPathAddQuadCurveToPoint(p, NULL, points[0].x, points[0].y, points[1].x, points[1].y); break; case kCGPathElementAddCurveToPoint: CGPathAddCurveToPoint(p, NULL, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y); break; case kCGPathElementCloseSubpath: CGPathCloseSubpath(p); break; default: CGPathRelease(p); return NO; } } self.path = p; CGPathRelease(p); // Signal success return YES; } - (void)dealloc { CGPathRelease(path); [super dealloc]; } @end