In my ViewController class, I have a function:
func updateTimes() {
// (code)
}
I create a timer:
class ViewController: NSViewController {
var timer = Timer.scheduledTimer(timeInterval: 5,
target: self,
selector:
#selector(ViewController.updateTimes),
userInfo: nil,
repeats: true)
The compiler is happy with this. At runtime, when the timer fires, I get an exception:
unrecognized selector sent to instance 0x6000000428b0
Am I doing something obviously wrong?
As I wrote as a comment on NaGib ToroNgo's answer, he has given us a nice suggestion.
The selector may not be sent to the instance of ViewController
.
I guess the ViewController
would be taking this form:
class ViewController: UIViewController {
var timer = Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(ViewController.updateTimes),
userInfo: nil,
repeats: true)
//...(Other property declarations or method definitions)...
func updateTimes() {
// (code)
}
}
The variable timer
is declared as an instance property, and self
is used in an initial value of timer
. (In some old versions of Swift, this sort of usage caused error, so I was thinking that this line exists in any of the methods.)
In the current version of Swift (tested with Swift 3.1/Xcode 8.3.3), the code above does not cause error, but self
is interpreted as a method reference of self()
method declared in NSObjectProtocol
. So, Selector("updateTimes")
is sent to the closure representing the method reference (curried function), not to the instance of the ViewController
.
The closure does not have a method named updateTimes
, which caused the exception:
unrecognized selector sent to instance
Move the initial value code into some instance context, and then self
represents the instance of the ViewController
:
class ViewController: UIViewController {
var timer: Timer? //<- Keep `timer` as an instance property, but move the initial value code into `viewDidLoad()`.
//...(Other property declarations or method definitions)...
override func viewDidLoad() {
super.viewDidLoad()
//Do initialize the timer in the instance context.
timer = Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(self.updateTimes),
userInfo: nil,
repeats: true)
//...
}
//In Swift 3, `@objc` is not needed, just for a preparation for Swift 4
@objc func updateTimes() {
// (code)
}
}
I believe this does not cause unrecognized selector
exception.