Efficient Drawing Storage Method?
I'm developing a basic drawing app that has a few classes. One of these is a "Line" class that stores some info on a line the user can draw. When the user drags round the screen, a line is created for each movement of their finger, so a line is drawn following their finger. I store all the line objects in an NSArray and redraw each time something changes. However, since the array just keeps getting bigger, and eventually starts to slow down. Is there any way to just draw the new lines, or a better storage mechanism for the lines?
EDIT:
Read the answer below, but setNeedsDisplayInRect:
doesn't seem to be working. I am calling it like so:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *t in touches) {
//add line to array w/ x and y values from touch
[self setNeedsDisplayInRect:[self rectForLine:line]];
}
}
-(CGRect)rectForLine:(Line*)line {
CGFloat x1 = [line begin].x;
CGFloat y1 = [line begin].y;
CGFloat x2 = [line end].x;
CGFloat y2 = [line end开发者_开发技巧].y;
CGFloat originX = (x1>x2) ? x1 : x2;
CGFloat originY = (y1<y2) ? y1 : y2;
CGFloat diffX = ((x1>x2) ? x1 : x2) - originX;
CGFloat diffY = ((y1>x2) ? y1 : y2) - originY;
return CGRectMake(originX, originY, diffX, diffY);
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 10.0);
CGContextSetLineCap(context, kCGLineCapRound);
//[[UIColor blackColor] set];
for (Line *line in completeLines) {
if (CGRectContainsPoint(rect, [line begin]) && CGRectContainsPoint(rect, [line end])) {
//draw line onto the screen
}
}
If a "line" is just a pair of points in your data model, that's not the part slowing you down.
Your perf problem is that you're redrawing the whole thing every line that gets added, which is O(n^2) or very specifically a Schlemiel-the-Painter's algorithm.
The simplest improvement, assuming you're drawing inside the -drawRect:
of a UIView, is probably to only invalidate and redraw the rect that contains the new line. Based on the start and end points, you can create the invalid rect to send to -setNeedsDisplayInRect:
, and then in your drawRect, look at all your lines, and only draw the ones that fall inside the rect. This bounds your draw performance to the size of the lines and to a much lesser degree, the drawing that's "already there".
精彩评论