title: CALayer with Animated Path Content, Make Inspectable/Designable
body: <p>I made a custom circular progress view by subclassing <code>UIView</code>, adding a <code>CAShapeLayer</code> sublayer to its layer and overriding <code>drawRect()</code> to update the shape layer's <code>path</code> property.</p>
  
  <p>By making the view <code>@IBDesignable</code> and the <code>progress</code> property <code>@IBInspectable</code>, I was able to edit its value in Interface Builder and see the updated bezier path in real time. Non-essential, but really cool!</p>
  
  <p>Next, I decided to make the path animated: Whenever you set a new value in code, the arc indicating the progress should "grow" from zero length to whatever percentage of the circle is achieved (think of arcs in the Activity app in apple Watch).</p>
  
  <p>To achieve this, I swapped my <code>CAShapeLayer</code> sublayer by a custom <code>CALayer</code> subclass that has a <code>@dynamic</code> (<code>@NSManaged</code>) property, observed as key for ananimation (I implemented <code>needsDisplayForKey()</code>, <code>actionForKey()</code>, <code>drawInContext()</code> etc. ).</p>
  
  <p>My <strong>View</strong> code (the relevant parts) looks something like this:</p>
  
  <pre><code>// Triggers path update (animated)
  private var progress: CGFloat = 0.0 {
      didSet {
          updateArcLayer()
      }
  }
  
  // Programmatic interface:
  // (pass false to achieve immediate change)
  func setValue(newValue: CGFloat, animated: Bool) {
      if animated {
          self.progress = newValue
      } else {
          arcLayer.animates = false
          arcLayer.removeAllAnimations()
          self.progress = newValue
          arcLayer.animates = true
      }
  }
  
  // Exposed to Interface Builder's  inspector: 
  @IBInspectable var currentValue: CGFloat {
      set(newValue) {
          setValue(newValue: currentValue, animated: false)
          self.setNeedsLayout()
      }
      get {
          return progress
      }
  }
  
  private func updateArcLayer() {
      arcLayer.frame = self.layer.bounds
      arcLayer.progress = progress
  }
  </code></pre>
  
  <p>And the <strong>layer</strong> code:</p>
  
  <pre><code>var animates: Bool = true
  @NSManaged var progress: CGFloat
  
  override class func needsDisplay(forKey key: String) -&gt; Bool {
      if key == "progress" {
          return true
      }
      return super.needsDisplay(forKey: key)
  }
  
  override func action(forKey event: String) -&gt; CAAction? {
      if event == "progress" &amp;&amp; animates == true {
          return makeAnimation(forKey: event)
      }
      return super.action(forKey: event)
  }
  
  override func draw(in ctx: CGContext) {
      ctx.beginPath()
  
      // Define the arcs...
      ctx.closePath()
      ctx.setFillColor(fillColor.cgColor)
      ctx.drawPath(using: CGPathDrawingMode.fill)
  }
  
  private func makeAnimation(forKey event: String) -&gt; CABasicAnimation? {
      let animation = CABasicAnimation(keyPath: event)
  
      if let presentationLayer = self.presentation() {
          animation.fromValue = presentationLayer.value(forKey: event)
      }
  
      animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
      animation.duration = animationDuration
      return animation
  }
  </code></pre>
  
  <p>The animation works, but now <strong>I can't get my paths to show in Interface Builder</strong>.</p>
  
  <p>I have tried implementing my view's <code>prepareForInterfaceBuilder()</code> like this:</p>
  
  <pre><code>override func prepareForInterfaceBuilder() {
      super.prepareForInterfaceBuilder()
  
      self.topLabel.text = "Hello, Interface Builder!"
      updateArcLayer()
  }
  </code></pre>
  
  <p>...and the label text change is reflected in Interface Builder, but the path isn't rendered.</p>
  
  <p><strong>Am I missing something?</strong></p>