UIBezierPath绘图占用CPU的100%

时间:2015-01-14 21:57:26

标签: ios objective-c core-graphics drawrect uibezierpath

每次移动用户的触摸屏幕时,我都会在屏幕上绘制UIBezierPath。这在Mac Pro上的模拟器上工作正常,但是一旦我将它移动到物理设备,绘图开始滞后很多。使用仪器,我检查了CPU的使用情况,并在用户绘图时达到100%。

这就成了问题,因为我有一个应该以30fps的速度发射的NSTimer,但是当CPU被图形重载时,计时器只会以10fps左右的速度发射。

如何优化绘图以使其不占用100%的CPU?

UITouch* lastTouch;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if(lastTouch != nil)
        return;

    lastTouch = [touches anyObject];
    [path moveToPoint:[lastTouch locationInView:self]];
    [self drawDot];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if([touches anyObject] == lastTouch)
        [self drawDot];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if([touches anyObject] == lastTouch)
        lastTouch = nil;
}

- (void)drawDot
{
    if(!self.canDraw)
        return;

    [path addLineToPoint:[lastTouch locationInView:self]];
    [self setNeedsDisplayInRect:CGRectMake([lastTouch locationInView:self].x-30, [lastTouch locationInView:self].y-30, 60, 60)];
}

- (void)drawRect:(CGRect)rect
{    
    CGColorRef green = [UIColor green].CGColor;
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGColorRef gray = [UIColor gray].CGColor;
    CGContextSetStrokeColor(context, CGColorGetComponents(gray));
    [shape stroke];

    CGContextSetStrokeColor(context, CGColorGetComponents(green));
    [path stroke];
}

2 个答案:

答案 0 :(得分:3)

你不应该在现代代码中使用-drawRect - 它已有30年历史,专为非常旧的硬件(25Mhz CPU,16MB RAM和无GPU)而设计,并且在现代硬件上存在性能瓶颈。

相反,您应该使用Core Animation或OpenGL进行所有绘图。核心动画可以与drawRect非常相似。

将此添加到视图的init方法中:

self.layer.contentsScale = [UIScreen mainScreen].scale;

并实施:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
   // basically the same code as you've got inDrawRect, although I recommend
   // trying Core Graphics (CGContextMoveToPoint(), CGContextAddLineToPoint(), 
   // CGContextStrokePath(), etc)
}

并重新绘制(在touchesMoved / etc中):

[self.layer setNeedsDisplay];

我还会更新您的触摸事件代码,以便附加到NSMutableArray点(可能在[NSValue valueWithCGPoint:location]中编码)。这样,您在响应触摸事件时就不会创建图形路径。

答案 1 :(得分:3)

寻找高效drawRect的好地方:是几年前的wwdc视频:https://developer.apple.com/videos/wwdc/2012/?id=238。大约26米,他开始调试一个非常简单的绘画应用程序,它非常类似于你所描述的。在第30分钟,他在第一次优化setNeedsDisplayInRect后开始优化:(你已经在做了)。

短篇小说:他使用图像作为已经绘制的图像的后备存储,这样每个drawRect:调用他只绘制1个图像+非常短的附加线段,而不是每次都绘制极长的路径。