When animating views on a CocoaTouch application we usually rely on the + animateWithDuration:animations: method of UIView. This approach works remarkably well for growing/shrinking, hiding/showing, and moving around UI elements, but what if we need a finer control? What if we need to implement something like a game loop, where every frame the screen is updated based on the new state of the world model?

In those cases + animateWithDuration:animations: is not enough. We need a timer object that periodically “ticks” and updates our complex view.

I said timer, but don’t even think about using NSTimer!

The class that does the job is CADisplayLink.

A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.

And this is why CADisplayLink is the go-to when we need to do a model based animation. With it we can run our view update code in sync with the screen refresh.

Here’s a snippet on how to setup CADisplayLink, since I always forget about it…

@property (nonatomic, strong) CADisplayLink *timer;
@property (nonatomic, assign) NSTimeInterval lastTimestamp;

//...

- (void)startScreenUpdate {
    self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(tick:)];
    [self.timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)tick:(CADisplayLink *)sender {
    if (self.lastTimestamp == 0) {
        // first tick, nothing to do
        return;
    }

    CGFloat elapsedTime = sender.timestamp  - self.lastTimestamp;
    self.lastTimestamp = sender.timestamp;

    [self updateMovingObjectPositionWithElapsedTime:elapsedTime];

    //...
}

Food for thoughts

  • Provide an example where there’s actually moving stuff.
  • Look deeper into why CADisplayLink is better suited that NSTimer to animate the view.