title: iOS: Why UIView's drawRect has better performance than CALayer's drawInContext
body: <p>I am currently learning drawing with UIView and CALayer. I quickly did a drawing app to experiment with the two classes. I noticed CALayer had worse performance than UIView. Here is the code:</p>
  
  <p>myView.m</p>
  
  <pre><code>@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&lt;UITouch *&gt; *)touches
  {
      NSArray *touchesArray = [touches allObjects];
      UITouch *touch = (UITouch *)[touchesArray objectAtIndex:0];
      return [touch locationInView:self];
  }
  
  - (void)touchesBegan:(NSSet&lt;UITouch *&gt; *)touches withEvent:(UIEvent *)event
  {
      CGPoint point = [self getPoint:touches];
      self.drawCanvas.points = [[NSMutableArray alloc] init];
      self.drawCanvas.startPoint = point;
  }
  
  - (void)touchesEnded:(NSSet&lt;UITouch *&gt; *)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&lt;UITouch *&gt; *)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
  </code></pre>
  
  <p>drawingView.h</p>
  
  <pre><code>@interface drawingView : UIView
  
  @property (nonatomic, assign) CGPoint startPoint;
  @property (nonatomic, strong) NSMutableArray *points;
  
  @end
  </code></pre>
  
  <p>drawingView.m</p>
  
  <pre><code>@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
  </code></pre>
  
  <p>I also have "drawingLayer" which is essentially the same thing as "drawingView", except it a subclass of CALayer and does the same drawing in "drawInContext". </p>
  
  <p>What I found was the drawRect has much better performance, the drawing is almost in-sync with the touch position, with very minor lag.
  Why is this the case? I expected the CALayer drawing to be at least the same, if not better. In fact, someone told me today that drawing in CALayer is hardware-accelerated, which is the preferred way if performance is a concern. Certainly this is NOT the case in my little experiment. Why?</p>