2015-12-01 2 views
2

J'apprends actuellement le dessin avec UIView et CALayer. J'ai rapidement fait une application de dessin pour expérimenter avec les deux classes. J'ai remarqué que CALayer avait de moins bonnes performances que UIView. Voici le code:iOS: Pourquoi drawRect de UIView a de meilleures performances que drawInContext de CALayer

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 

J'ai aussi "drawingLayer" qui est essentiellement le même chose comme "drawingView", sauf une sous-classe de CALayer et fait le même dessin dans "drawInContext".

Ce que j'ai trouvé a été le drawRect a de meilleures performances, le dessin est presque synchronisé avec la position tactile, avec un décalage très mineur. Pourquoi est-ce le cas? Je m'attendais à ce que le dessin de CALayer soit au moins le même, sinon meilleur. En fait, quelqu'un m'a dit aujourd'hui que le dessin dans CALayer est accéléré par le matériel, ce qui est la méthode préférée si la performance est un problème. Ce n'est certainement pas le cas dans ma petite expérience. Pourquoi?

+0

animations CALayer peut le faire apparaître plus lent en mouvement. Peut-être que c'est ce que vous observez –

+0

Vous sentez-vous plus lent, ou est-ce vraiment? Avez-vous utilisé des instruments pour vérifier cela? D'ailleurs, avez-vous essayé de mettre à jour le cgPath d'un CAShapeLayer à la place? Cela pourrait également améliorer les performances. – Lepidopteron

Répondre

0

Cela peut être dû à l'animation par défaut de CALayer.

Essayez de remplacer le action(forKey event: String) -> CAAction? et toujours revenir nil tandis que les sous-classement classe CALayer