iOS Timer Tutorial
In this iOS Timer tutorial, you’ll learn how timers work, affect UI responsiveness and battery and how to work with animations using CADisplayLink. By Fabrizio Brancati.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
iOS Timer Tutorial
20 mins
- Getting Started
- Creating Your First Timer
- Adding Timer Tolerance
- Trying Out Timers in the Background
- Understanding Run Loops
- Utilizing Run Loop Modes
- Adding a Task Completion Animation
- Showing the Animation
- Stopping a Timer
- Using CADisplayLink for Smoother Animations
- CADisplayLink to the Rescue!
- Where to Go From Here?
CADisplayLink to the Rescue!
CADisplayLink
is called once per frame and will try to synchronize with the real screen frames as much as possible. With that, you’ll have full access to all 16ms available and you’ll be sure iOS won’t drop any frames. Even on the new iPads with a ProMotion display at 120Hz, you’ll not miss a frame!
To use CADisplayLink
, you must replace animationTimer
with a new type.
Replace the following code:
var animationTimer: Timer?
With the following code:
var displayLink: CADisplayLink?
You have replaced the Timer
with CADisplayLink
. CADisplayLink
is a timer representation that is bound to the display’s vsync. This means that the GPU of the device will stall until the physical screen is ready to process more GPU commands. That way, you ensure a smoother animation.
Replace the following code:
var startTime: TimeInterval?, endTime: TimeInterval?
With the following code:
var startTime: CFTimeInterval?, endTime: CFTimeInterval?
You have replaced TimeInterval
optionals with CFTimeInterval
optionals to store time elapsed in seconds and work with CADisplayLink
nicely.
Replace showCongratulationAnimation()
with the following code:
func showCongratulationAnimation() {
// 1
height = UIScreen.main.bounds.height + balloon.frame.size.height
balloon.center = CGPoint(x: UIScreen.main.bounds.width / 2,
y: height + balloon.frame.size.height / 2)
balloon.isHidden = false
// 2
startTime = CACurrentMediaTime()
endTime = animationDuration + startTime!
// 3
displayLink = CADisplayLink(target: self,
selector: #selector(updateAnimation))
displayLink?.add(to: RunLoop.main, forMode: .common)
}
In the code above, you:
- Set the animation height, set the balloon center position, and make the animation visible – just like you previously did.
- Initialize
startTime
withCACurrentMediaTime()
(instead ofDate()
). - Set
displayLink
to aCADisplayLink
. Then, adddisplayLink
to the mainRunLoop
withcommon
mode.
Next, replace the updateAnimation()
with the following code:
// 1
@objc func updateAnimation() {
guard
let endTime = endTime,
let startTime = startTime
else {
return
}
// 2
let now = CACurrentMediaTime()
if now >= endTime {
// 3
displayLink?.isPaused = true
displayLink?.invalidate()
balloon.isHidden = true
}
let percentage = (now - startTime) * 100 / animationDuration
let y = height - ((height + balloon.frame.height / 2) / 100 *
CGFloat(percentage))
balloon.center = CGPoint(x: balloon.center.x +
CGFloat.random(in: -0.5...0.5), y: y)
}
Here, you:
- Add
@objc
to the method signature. This is becauseCADisplayLink
has a selector parameter that requires an Objective-C selector. - Replace the
Date()
initialization with a CoreAnimation date.CACurrentMediaTime
returns the current absolute time in seconds. - Change
animationTimer.invalidate()
call with theCADisplayLink
‘s pause and invalidate. This will also remove the display link from all run loop modes and have the display link release its target.
Build and run one last time!
Good job! You have now successfully replaced a Timer
based animation with a CADisplayLink
in order to create a smoother animation. The difference is small, but users really enjoy smooth and seamless animations — even on older devices.
Where to Go From Here?
You can download the finished project using the Download Materials button at the top or bottom of this tutorial.
In this tutorial, you’ve learned how the Timer
class works on iOS, what a RunLoop
is and how they can help you with your app’s responsiveness, and to use CADisplayLink
instead of Timer
for smooth animations.
If you want to learn more about scheduling tasks, check out Grand Central Dispatch Tutorial for Swift 4: Part 1/2 and Grand Central Dispatch Tutorial for Swift 4: Part 2/2. Or, if you want to know more about animations, check out our book iOS Animations by Tutorials.
If you have any questions or comments about this tutorial, please join the forum discussion below!