Ring-Jarvi Ring-Jarvi - 2 years ago 196
Swift Question

NSTimer not firing propery

I have set up a timer class to firer when the viewDidLoad(). I want to have a timer on multiple view controllers thoughout the app. If you have a better solution to a accurate timer on multiple views please suggest.

Viewcontroller -> One of the views that needs a timer

override func viewDidLoad() {

func setupTimer() {

// Setupt the timer, this will call the timerFired method every second
var timer = NSTimer(
timeInterval: 1.0,
target: self,
selector: #selector(TestTimer.timerFired()),//<- Error Code
userInfo: nil,
repeats: true)

The Error Code: Use of instance member 'timerFired' on type 'TestTimer',did you mean to use a value of type 'TestTimer' instead?

Timer Class -> Checks start date compared to current date/time for a accurate timer

class TestTimer: NSTimer {

var timer = NSTimer()
// Converter changes String into NSDate
var startDate = converter("Tue, 26 Apr 2016 09:01:00 MDT")
// Function to be fired
func timerFired() {

let now = NSDate()
let difference = now.timeIntervalSinceDate(self.startDate)

// Format the difference for display
// For example, minutes & seconds
let dateComponentsFormatter = NSDateComponentsFormatter()


Answer Source

The error you're getting is pretty obscure. What it's trying to tell you is you should remove the () from the end of your timerFired in the #selector.

var timer = NSTimer(
    timeInterval: 1.0,
    target: self,
    selector: #selector(TestTimer.timerFired),
    userInfo: nil,
    repeats: true)

However, this isn't going to make your code how you want it to work – as self in the timer declaration refers to the view controller, not the timer. I would recommend you create a wrapper class for NSTimer, along with a delegate pattern in order to achieve what you want.

You should note that the documentation states that you shouldn't attempt to subclass NSTimer, so you could do something like this instead:

// the protocol that defines the timerDidFire callback method
protocol TimerDelegate:class {
    func timerDidFire(cumulativeTime:NSTimeInterval)

// your timer wrapper class
class TimerWrapper {

    // the underlying timer object
    weak private var _timer:NSTimer?

    // the start date of when the timer first started
    private var _startDate = NSDate()

    // the delegate used to implement the timerDidFire callback method
    weak var delegate:TimerDelegate?

    // start the timer with a given firing interval – which could be a property
    func startTimer(interval:NSTimeInterval) {

        // if timer already exists, make sure to stop it before starting another one
        if _timer != nil {

        // reset start date and start new timer
        _startDate = NSDate()
        _timer = NSTimer.scheduledTimerWithTimeInterval(interval,
                                                        target: self,
                                                        selector: #selector(timerDidFire),
                                                        userInfo: nil, repeats: true)

    // invalidate & deallocate the timer,
    // make sure to call this when you're done with the timer
    func stopTimer() {
        _timer = nil

    // make sure to stop the timer when the wrapper gets deallocated
    deinit {

    // called when the timer fires
    @objc func timerDidFire() {

        // get the change in time, from when the timer first fired to now
        let deltaTime = NSDate().timeIntervalSinceDate(_startDate)

        // do something with delta time

        // invoke the callback method

You can then use it like this:

// your view controller class – make sure it conforms to the TimerDelegate
class ViewController: UIViewController, TimerDelegate {

    // an instance of the timer wrapper class
    let timer = TimerWrapper()

    override func viewDidLoad() {

        // set the timer delegate and start the timer – delegate should be set in viewDidLoad,
        // timer can be started whenever you need it to be started.
        timer.delegate = self

    func timerDidFire(cumulativeTime: NSTimeInterval) {

        // do something with the total time

        let dateComponentsFormatter = NSDateComponentsFormatter()
        let text = dateComponentsFormatter.stringFromTimeInterval(cumulativeTime)
        label.text = text

As far as the appropriateness of using an NSTimer here goes, as you're only using a time interval of 1 second, an NSTimer is suitable. By taking the time interval over the total timer duration, you can average out any small firing inaccuracies.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download