skip to Main Content

I’m trying to learn how to use a timer in Swift, and every solution I look up is broken somehow or beyond my understanding.

I’ve tried with a closure, and without.

With a closure, I can actually get the app to run without crashing, but the timer just repeats 60, it doesn’t count down and I don’t know why.

let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
        var secondsRemaining = 60
        print(secondsRemaining)
        secondsRemaining -= 1
    })

I’ve also tried using an @objc func with selector, but my app crashes right away with error Thread 1: "-[__SwiftValue countdown]: unrecognized selector sent to instance 0x600002970e40" (I haven’t even gotten to trying the count down yet).

class ViewController: UIViewController {

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(countdown), userInfo: nil, repeats: true)
        
        @objc func countdown() {
            print("fire")
        }
        …
        …
}

Any help is appreciated.

EDIT

If I place my variable outside the block, I get an error inside the block Instance member 'secondsRemaining' cannot be used on type 'ViewController'

class ViewController: UIViewController {

var secondsRemaining = 60
    
let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
            print(secondsRemaining)
            secondsRemaining -= 1
        })
}

But if I create a new project and put the timer inside viewDidLoad(), it works. I don’t know why.

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

var secondsRemaining = 60
    
let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
            print(secondsRemaining)
            secondsRemaining -= 1
        })
}
}

4

Answers


  1. Every time your timer fires, a new variable with an initial value of 60 is instantiated, thus always printing 60.
    You have to declare your counting variable outside:

    private var secondsRemaining = 60
    
    let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
    
        print(self.secondsRemaining)
        self.secondsRemaining -= 1
    })
    

    Or:

    class ViewController: UIViewController {
        private var secondsRemaining = 60
    
        let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(countdown), userInfo: nil, repeats: true)
            
        @objc func countdown() {
            print("fire")
            self.secondsRemaining -= 1
        }
    }
    
    Login or Signup to reply.
  2. You’re declaring counter inside the timer call. That’s why every time the timer executes it resets the counter to 60 seconds. You need to declare your timer outside the it’s call:

    var secondsRemaining = 60
    
    let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
            print(secondsRemaining)
            secondsRemaining -= 1
        })
    
    Login or Signup to reply.
  3. As mentioned in the comments above, don’t reset the variable every single time you get in the closure and change you timer to the following. Create a simple obj function to do whatever logic you want. Also name your functionalists meaningfully

    class XViewController: UIViewController {
    private var secondsRemaining:Int = 60
    
    let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(startScrolling), userInfo: nil, repeats: true)
    
    
    @objc func startScrolling() {
        print(secondsRemaining)
        secondsRemaining -= 1
    }
    

    }

    Login or Signup to reply.
  4. Here is the fixed code:

    class ViewController: UIViewController {
    
        private  var secondsRemaining = 60
    
        override func viewDidLoad() {
            super.viewDidLoad()
       
            let timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
                print(secondsRemaining)
                secondsRemaining -= 1
            })
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search