每次移动用户的触摸屏幕时,我都会在屏幕上绘制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];
}
答案 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个图像+非常短的附加线段,而不是每次都绘制极长的路径。