iOS:为什么UIView的drawRect比CALayer的drawInContext性能更好?

3

我目前正在学习使用UIView和CALayer进行绘图。我快速制作了一个绘图应用程序来尝试这两个类。我注意到CALayer的性能比UIView差。以下是代码:

myView.m

@interface myView()

@property (nonatomic, strong) UIImageView *background;

#ifdef USE_LAYER
@property (nonatomic, strong) drawingLayer *drawCanvas;
#else
@property (nonatomic, strong) drawingView  *drawCanvas;
#endif
@end

@implementation myView

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
    {
        self.background = [[UIImageView alloc] initWithFrame:frame];
        [self addSubview:self.background];
#ifdef USE_LAYER
        self.drawCanvas = [[drawingLayer alloc] init];
        self.drawCanvas.frame = frame;
        [self.layer addSublayer:self.drawCanvas];
#else
        self.drawCanvas = [[drawingView alloc] initWithFrame:frame];
        self.drawCanvas.backgroundColor = [UIColor clearColor];
        [self addSubview:self.drawCanvas];
#endif
    }
    return self;
}

- (CGPoint)getPoint:(NSSet<UITouch *> *)touches
{
    NSArray *touchesArray = [touches allObjects];
    UITouch *touch = (UITouch *)[touchesArray objectAtIndex:0];
    return [touch locationInView:self];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CGPoint point = [self getPoint:touches];
    self.drawCanvas.points = [[NSMutableArray alloc] init];
    self.drawCanvas.startPoint = point;
}

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CGPoint point = [self getPoint:touches];
    [self.drawCanvas.points addObject:[NSValue valueWithCGPoint:point]];
    self.background.image = [self imageFromLayer:self.layer];
    self.drawCanvas.points = nil;
    [self.drawCanvas setNeedsDisplay];
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CGPoint point = [self getPoint:touches];
    [self.drawCanvas.points addObject:[NSValue valueWithCGPoint:point]];
    [self.drawCanvas setNeedsDisplay];
}

- (UIImage *)imageFromLayer:(CALayer *)layer
{
    UIGraphicsBeginImageContext([layer frame].size);
    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return outputImage;
}

@end

drawingView.h

@interface drawingView : UIView

@property (nonatomic, assign) CGPoint startPoint;
@property (nonatomic, strong) NSMutableArray *points;

@end

drawingView.m

@implementation drawingView

- (void)drawRect:(CGRect)rect {
     CGContextRef context = UIGraphicsGetCurrentContext();
     CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);

     CGContextSetLineWidth(context, 2.0f);
     CGContextMoveToPoint(context, self.startPoint.x, self.startPoint.y);

     for (NSValue *point in self.points)
     {
         CGPoint location = [point CGPointValue];
         CGContextAddLineToPoint(context, location.x, location.y);
     }
     CGContextStrokePath(context);
}

@end

我还有一个名为“drawingLayer”的东西,它本质上与“drawingView”相同,只是它是CALayer的子类,并在“drawInContext”中进行相同的绘制。
我发现drawRect具有更好的性能,绘图几乎与触摸位置同步,延迟非常小。为什么会这样呢?我原以为CALayer绘图至少应该与drawRect一样好甚至更好。事实上,今天有人告诉我,在CALayer中绘图是硬件加速的,如果性能是一个问题,这是首选的方式。但在我的小实验中显然并不是这种情况。为什么呢?

CALayer的动画可以让它看起来移动得更慢。也许这就是你观察到的现象。 - Philip De Vries
你感觉它变慢了,还是真的变慢了?你用Instruments验证过吗?此外,你尝试过更新CAShapeLayer的cgPath吗?这也可能提高性能。 - Lepidopteron
1个回答

0

这可能是由于CALayer的默认动画引起的。

尝试在子类化CALayer类时覆盖action(forKey event: String) -> CAAction?并始终返回nil


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接