Correct handling / cleanup / etc of CADisplayLink in Swift custom animation?
<p>Consider this trivial sync animation using <code>CADisplayLink</code>,</p>

<pre><code>var link:CADisplayLink?
var startTime:Double = 0.0
let animTime:Double = 0.2
let animMaxVal:CGFloat = 0.4

private func yourAnim()
    {
    if ( link != nil )
        {
        link!.paused = true
        //A:
        link!.removeFromRunLoop(
          NSRunLoop.mainRunLoop(), forMode:NSDefaultRunLoopMode)
        link = nil
        }

    link = CADisplayLink(target: self, selector: #selector(doorStep) )
    startTime = CACurrentMediaTime()
    link!.addToRunLoop(
      NSRunLoop.currentRunLoop(), forMode:NSDefaultRunLoopMode)
    }

func doorStep()
    {
    let elapsed = CACurrentMediaTime() - startTime

    var ping = elapsed
    if (elapsed &gt; (animTime / 2.0)) {ping = animTime - elapsed}

    let frac = ping / (animTime / 2.0)
    yourAnimFunction(CGFloat(frac) * animMaxVal)

    if (elapsed &gt; animTime)
        {
        //B:
        link!.paused = true
        link!.removeFromRunLoop(
          NSRunLoop.mainRunLoop(), forMode:NSDefaultRunLoopMode)
        link = nil
        yourAnimFunction(0.0)
        }
    }

func killAnimation()
    {
    // for example if the cell disappears or is reused
    //C:
    ????!!!!
    }
</code></pre>

<p>There seems to be various problems.</p>

<p>At (A:), even though <code>link</code> is not null, it may not be possible to remove it from a run loop.  (For example, someone may have initialized it with <code>link = link:CADisplayLink()</code> - try it for a crash.)</p>

<p>Secondly at (B:) it seems to be a mess ... surely there's a better (and more Swift) way, and what if it's nil even though the time just expired?</p>

<p>Finally in (C:) if you want to break the anim ... I got depressed and have no clue what is best.</p>

<p>And really the code at A: and B: should be the same call right, kind of a clean-up call.</p>