UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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?

3      

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
                      selector:@selector(onTick:)
                      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) {
    //...do 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.

4      

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".

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

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.