Initializing Swift properties that require “self” as an argument

i0S Swift Issue

Question or problem in the Swift programming language:

I have a Swift class that I’d like to look something like this:

class UpdateManager {
  let timer: NSTimer

  init() {
    timer = NSTimer(timeInterval: 600, target: self, selector: "check", userInfo: nil, repeats: true)
  }

  func check() {
    // Do some stuff
  }
}

However, Swift doesn’t like the fact that I’m passing self to the NSTimer initializer. Am I breaking some pattern here? How is one supposed to accomplish initialization like this?

How to solve the problem:

Solution 1:

You’ve found the primary use case of the Implicitly Unwrapped Optional.

  • You need to access self from init, before timer is initialized.
  • Otherwise, timer should never be nil, so you shouldn’t have to check it outside of init.

So, you should declare let timer: NSTimer!.

Solution 2:

It’s possible that Swift 2 has changed what works. I’m using code like the following:

@objc class Test : NSObject {
    var timer : NSTimer!
    init text() {
        super.init()
        timer = NSTimer(timeInterval: 1.0, target: self, selector: "timerFired:", userInfo: nil, repeats: true)
        NSRunLoop.mainRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
    }
}

Needed both @objc declaration and NSObject subclass.
Also timer needs to be a var, not let.

Solution 3:

Aside from the implicitly unwrapped optional, I found that to get the code working I needed to subclass NSObject and to also add the timer to current run loop.

class UpdateManager:NSObject {
    let timer: NSTimer!

    override init() {
        super.init()
        timer = NSTimer(timeInterval: 600, target: self, selector: "check", userInfo: nil, repeats: true)
        NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSDefaultRunLoopMode)
    }


    func check() {
        // Do some stuff

    }
}

Updated code based on comments – thank you to jtbandes and Caroline

class UpdateManager {
    let timer: NSTimer!

   init() {

        timer = NSTimer.scheduledTimerWithTimeInterval(600,
            target: self,
            selector: "check",
            userInfo: nil,
            repeats: true)
    }


   @objc func check() {
        // Do some stuff

    }
}

Hope this helps!