NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

Loop countdown timer: why @objc

Forums > SwiftUI

I'm trying to make an interval countdown timer with simply 2 buttons that each set the start time and begin counting down to zero and then repeat (keeping counts of repeats): one button at 15 seconds, the other at 30 seconds. I've found a number of tutorials and samples with all very different ways of doing this and got extra stumped when an example here used "@objc". Swift is the first language I have tried learning and as a beginner, I try to steer away from objective-c and there is plenty to learn in SwiftUI and Swift alone.

Here is the example with @objc: The ultimate guide to Timer from 1/3/21

Pauls writes: "Note: That needs to use @objc because Timer uses the target/action approach to method calls."

Yet, in all the other tutorials that use Timer, none have @objc. All the other tutorials from other sources use .onReceive. For example, Paul's here Counting down with a Timer from 4/18/20

So the lesson that is 9 months more recent requires @objc.

Can anyone explain what is going on or help me get on track?


In Objective-C, you could call another function using its name, also known as a selector. You did this through a syntax like this:

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self
                      userInfo: nil repeats:NO];

Swift doesn't have the concept of selectors. You can pass a function directly into another function as a first-class value. But for older APIs that were built for Objective-C and take a selector, Swift has the #selector keyword. And since this is using the Objective-C runtime, you have to annotate your code with the @objc attribute.

So the above ObjC example becomes this in Swift:

let timer = Timer.scheduledTimer(timeInterval: 2.0,
                                 target: self,
                                 selector: #selector(onTick),
                                 userInfo: nil,
                                 repeats: true)

In Swift, we don't use the concept of selectors. You can either pass your function directly as a parameter (since functions are first-class values in Swift), like so:

let timer = Timer.scheduledTimer(timeInterval: 2.0, repeats: false, block: onTick)

Or use a closure instead of passing a function:

let timer = Timer.scheduledTimer(timeInterval: 2.0, repeats: false) {
    // something here

You will note, though, that the Swift version doesn't have a userInfo parameter. If you need one, you would have to use the ObjC method. Also, if you are doing this in UIKit, a lot of which is still ObjC-based at its core, you will probably need to use the selector version.

It's essentially a difference between a string-based API (selectors are really just special strings behind the scenes) and a function-based API.


Oh, forgot to addess the onReceive part...

With onReceive, we don't need to use a selector and @objc for two reasons:

  1. SwiftUI is not Objective-C based
  2. onReceive isn't being called directly by the timer. You'll notice that in that example there is no function or closure passed in when the timer is created. Instead, onReceive observes the timer and is triggered when the timer fires. It ultimately involves the Combine framework, which is all about observing values over a period of time. It's the difference between saying "Hey Timer, when you fire off, call this function to do something" versus "Hey SwiftUI View, keep an eye on this Timer and when it changes, do something".


Hacking with Swift is sponsored by Essential Developer

SPONSORED From March 20th to 26th, you can join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer!

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.