title: Drawing performance over time for a UIBezierPath with Swift for iOS
body: <p>I'm trying to understand different drawing methods in Swift and why they perform as they do.</p>
  
  <p>The below code draws smooth lines using a <code>UIBezierPath</code>, project available from <a href="https://github.com/limhowe/LimSignatureView" rel="nofollow">https://github.com/limhowe/LimSignatureView</a></p>
  
  <p>Initially the performance of the code below is highly responsive when the user begins touching the screen. However, over time, the longer the duration of touching and moving on the screen, the performance begins to lag and the drawing displayed doesn't keep up and isn't accurate (some points appear to be missed). The performance only returns to being highly responsive once touching the screen ends and touching the screen begins again for a new drawing.</p>
  
  <hr>
  
  <p>Things I've noticed:</p>
  
  <ul>
  <li><p>When <code>self.setNeedsDisplay()</code> is commented out (in <code>override func touchesMoved</code>), there is no drawing displayed during touching the screen, but once lifting the finger triggering <code>override func touchesEnded</code>, the final result is a perfect drawing, with no lagging or inaccurate drawing points no matter how long the duration. (This is the result ideally wanted and displayed while drawing.)</p></li>
  <li><p>When <code>beizerPath.removeAllPoints()</code> is commented out (in <code>override func touchesEnded</code>) lagging continues to occur even after the user lifts their finger and starts touching the screen again.</p></li>
  <li><p>It seems that <code>beizerPath.removeAllPoints()</code> might reset the lagging, while <code>self.setNeedsDisplay()</code> might be causing lagging over time.</p></li>
  <li><p>When increasing <code>beizerPath.lineWidth</code> to from 2 to a larger width (e.g. 50 or 100), the drawing tends to lag slightly.</p></li>
  </ul>
  
  <hr>
  
  <p>Hmmm. I'm confused as to why this is all is as it is.</p>
  
  <ul>
  <li><p>What exactly is going on here with the lagging over time?</p></li>
  <li><p>What is the relationship between <code>beizerPath.removeAllPoints()</code> and <code>self.setNeedsDisplay()</code> and the lagging? </p></li>
  <li><p>Why does increasing <code>beizerPath.lineWidth</code> cause some minor lagging?</p></li>
  <li><p>What might else be causing lagging?</p></li>
  <li><p>Could removing some of the points while drawing improve performance, and if so, how can that be acheived?</p></li>
  <li><p>What needs to be modified in the below code to ensure that perfect drawing continues overtime with no lagging?</p></li>
  </ul>
  
  <p>Appreciate any enlightened feedback and improvements to the code. Thank you.</p>
  
  <pre><code>//  LimSignatureView.swift
  //  SwiftSignatureView
  //
  //  Created by MyAdmin on 3/6/15.
  //  Copyright (c) 2015 MyAdmin. All rights reserved.
  //
  
  import UIKit
  
  class LimSignatureView: UIView {
  
      var beizerPath: UIBezierPath = UIBezierPath()
      var incrImage : UIImage?
      var points : [CGPoint] = Array&lt;CGPoint&gt;(count: 5, repeatedValue: CGPointZero)
      var control : Int = 0
  
      var lblSignature : UILabel = UILabel()
      var shapeLayer :   CAShapeLayer?
  
      required init(coder aDecoder: NSCoder) {
          fatalError("init(coder:) has not been implemented")
      }
  
      // Only override drawRect: if you perform custom drawing.
      // An empty implementation adversely affects performance during animation.
      override func drawRect(rect: CGRect) {
          // Drawing code
          incrImage?.drawInRect(rect)
          beizerPath.stroke()
  
          // Set initial color for drawing    
          UIColor.redColor().setFill()
          UIColor.redColor().setStroke()
          beizerPath.stroke()
      }
  
      override init(frame: CGRect) {
          super.init(frame: frame)
  
          var lblHeight: CGFloat = 61.0
          self.backgroundColor = UIColor.blackColor()
          beizerPath.lineWidth = 2.0
          lblSignature.frame = CGRectMake(0, self.frame.size.height/2 - lblHeight/2, self.frame.size.width, lblHeight);
          lblSignature.font = UIFont (name: "HelveticaNeue-UltraLight", size: 30)
          lblSignature.text = "Sign Here";
          lblSignature.textColor = UIColor.lightGrayColor()
          lblSignature.textAlignment = NSTextAlignment.Center
          lblSignature.alpha = 0.3;
          self.addSubview(lblSignature)
      }
  
      // MARK : - TOUCH Implementation
  
      override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
          if lblSignature.superview != nil {
              lblSignature.removeFromSuperview()
          }
  
          control = 0;
          var touch = touches.anyObject() as UITouch
          points[0] = touch.locationInView(self)
  
          var startPoint = points[0];
          var endPoint = CGPointMake(startPoint.x + 1.5, startPoint.y
              + 2);
  
          beizerPath.moveToPoint(startPoint)
          beizerPath.addLineToPoint(endPoint)
      }
  
      override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {  
          var touch = touches.anyObject() as UITouch
          var touchPoint = touch.locationInView(self)
          control++;
          points[control] = touchPoint;
  
          if (control == 4)
          {
              points[3] = CGPointMake((points[2].x + points[4].x)/2.0, (points[2].y + points[4].y)/2.0);
              beizerPath.moveToPoint(points[0])
              beizerPath.addCurveToPoint(points[3], controlPoint1: points[1], controlPoint2: points[2])
  
              self.setNeedsDisplay()
  
              points[0] = points[3];
              points[1] = points[4];
              control = 1;
          }
      }
  
      override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
          self.drawBitmapImage()
          self.setNeedsDisplay()
  
          beizerPath.removeAllPoints()
          control = 0
      }
  
      override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
          self.touchesEnded(touches, withEvent: event)
      }
  
      // MARK : LOGIC
  
      func drawBitmapImage() {
          UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0);
  
          if incrImage != nil {
              var rectpath = UIBezierPath(rect: self.bounds)
              UIColor.clearColor().setFill()
              rectpath.fill()
          }
          incrImage?.drawAtPoint(CGPointZero)
  
          //Set final color for drawing
          UIColor.redColor().setStroke()
          beizerPath.stroke()
  
          incrImage = UIGraphicsGetImageFromCurrentImageContext()
          UIGraphicsEndImageContext()
      }
  }
  </code></pre>