views:

43

answers:

1

I'm working on a barebones drawing app. I'm attempting to implement undo/redo capability, so I tell the view's undoManager to save the current image before updating the display. This works perfectly (yes, I understand that redrawing/saving the entire view is not incredibly efficient, but to solve this problem before attempting to optimize the code). However, as expected, when I 'undo' or 'redo', only the minute change is reflected. My goal is to have the whole finger stroke undone/redone. To do that, I told the undoManager to [beginUndoGrouping] in the [touchesBegan] method, and to [endUndoGrouping] in [touchesEnded]. That works for a bit, but after drawing a few strokes, the app crashes, and gdb exits with exc_bad_access. according to the crash reports, it's due to low memory

I'm very grateful for any insight you can give me.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

mouseDragged = YES;

currentPoint = [[touches anyObject] locationInView:self];

UIGraphicsBeginImageContext(drawingImageView.bounds.size);
[drawingImageView.image drawInRect:drawingImageView.bounds];

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineWidth(ctx, drawingWidth);
[drawingColor setStroke];

CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, previousPoint.x, previousPoint.y);
CGContextAddLineToPoint(ctx, currentPoint.x, currentPoint.y);
CGContextStrokePath(ctx);

[self.undoManager registerUndoWithTarget:drawingImageView selector:@selector(setImage:) object:drawingImageView.image];
drawingImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
previousPoint = currentPoint;

}

A: 

Even though you may not want to address the issue of saving and loading the entire view as an image, I'm pretty sure that's what's crashing your application here. Every time the user's finger moves, you are generating yet another image and adding it to the undo stack. No matter if you are using grouping with the undo / redo action, you're piling up a lot of memory-intensive images there, and your application will run out of memory at some point.

The undo grouping could still work for you, but you might want to store these drawn points instead, using something like -addPoint:, with a -removePoint: method as your undo action. Storing the points themselves will be far less memory intensive than saving the images.

However, if you're redrawing the image with each touch point, your undo action could take a while to run as it redraws the view for each point in the drawn trace. You may just want to forgo the undo grouping and just register an undo action for removing all of the points at once in your touches ended / cancelled methods.

Brad Larson