10

--EDITED WITH UPDATED INFORMATION--

What I wish to do is call a function named timerFunc once every five seconds using a NSTimer.scheduledTimerWithTimeInterval method, the issue seems is that during runtime, I get the error

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-      
[Animation.ViewController timerFunc:]: unrecognized selector sent to instance 0x7fe548d66040'

In the output log. I've been looking up other people's NSTimers to no avail, I see quite a few have the selector as selector: Selector("timerFunc:") instead of selector: Selector("timerFunc") both ways, however, give the error. Another thing is that both the timerFunc function and the NSTimer are inside of viewDidLoad, are there any issues with that? Any insight on the problem is greatly appreciated, thanks for reading.

timerFunc below

func timerFunc(){

    println("Timer")
}

NSTimer below

NSTimer.scheduledTimerWithTimeInterval(
        5.0,
        target: self,
        selector: Selector("timerFunc"),
        userInfo: nil,
        repeats: true)
Althonos
  • 131
  • 1
  • 9
  • 1
    What is the signature of your timerFunc? – vacawama Sep 14 '14 at 23:01
  • @vacawama Signature? Currently I'm trying to get NSTimer to work, so my timerFunc is only a `println("Timer")` I added my timerFunc to the main question. I've figured out my previous question, it was just that I didn't need to call timeInterval:, it messed it up for some reason. The current issue is that it doesn't give me an error in the editor, but when I run it the output log says `Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Animation.ViewController timerFunc]: unrecognized selector sent to instance 0x7fcc53e67010` among several lines of gibberish. – Althonos Sep 14 '14 at 23:34
  • I was just making sure your `timerFunc` didn't take a parameter. Yours doesn't, so that isn't the problem. Is your `timerFunc` a method of the `ViewController`? – vacawama Sep 15 '14 at 01:07
  • @vacawama My timerFunc is a function inside of viewDidLoad, which is inside of ViewController. I tested to see if it could be called by my NSTimer by writing a `timerFunc()` right next to my NSTimer location, proving it is accessible to where my NSTimer is. Perhaps, however, my NSTimer doesn't have access within my viewDidLoad? Should I create a whole new class with a special subclass for it? If so, what subclass? – Althonos Sep 15 '14 at 01:20
  • See my answer below. – vacawama Sep 15 '14 at 01:22
  • How to target class-level function in Swift? – sabiland Sep 22 '14 at 09:55

5 Answers5

11

Timers will not work with private method callbacks. Also, make sure your class inherits from NSObject. Pure Swift classes will not work.

More information can be found here: https://github.com/NxSoftware/NxSwiftTimer

Zorayr
  • 23,770
  • 8
  • 136
  • 129
Antoine
  • 23,526
  • 11
  • 88
  • 94
9

Another thing is that both the timerFunc function and the NSTimer are inside of viewDidLoad, are there any issues with that?

Yes. That is your problem. The timerFunc can't be nested inside of viewDidLoad, it must be a top level function at the same level as viewDidLoad.

class ViewController: UIViewController {

    override func viewDidLoad() {
        ....
        NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "timerFunc", userInfo: nil, repeats: true)
    }

    func timerFunc() {
        println("Timer")
    }

}

When the timer fires, it will call the function specified by the selector on the the object designated by target. That is, it will call self.timerFunc(). When your timerFunc() is nested inside of ViewDidLoad, it can't find it.

vacawama
  • 150,663
  • 30
  • 266
  • 294
  • As for why: methods invoked dynamically using a selector must be old school objc methods. All methods of a class inheriting from NSObject are by default, but if you're not extending NSObject you can mark them with `@objc`. – Kaylee Calderolla Sep 22 '14 at 12:25
3

My problem with this was the selector was pointing at a private function.

Karmie
  • 387
  • 2
  • 10
2

The first parameter of a Swift method does not include a label. All others generally do. You should expect the syntax to be:

NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "timerFunc", userInfo: nil, repeats: true)
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Yeah, I studied more closely to other people's code and came to that conclusion, however, now whenever I run it the output log gives me the error of `Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Animation.ViewController timerFunc]: unrecognized selector sent to instance 0x7fcc53e67010` How will I catch this exception>? – Althonos Sep 14 '14 at 23:36
  • I just clarified that it is implemented by commenting out my NSTimer and calling the timerFunc with a timerFunc() line. It does seem that it's just not recognizing timerFunc as a selector, although I don't know why. – Althonos Sep 15 '14 at 00:06
  • I just thought, does it matter where I have my NSTimer? Right now it's in viewDidLoad.. – Althonos Sep 15 '14 at 00:20
1

When using a selector in Swift you need to use the Selector() pseudo-function around the name of the function:

NSTimer.scheduledTimerWithTimeInterval(5.0,   target: self, 
                                            selector: Selector("timerFunc"), 
                                            userInfo: nil,
                                             repeats: true);

The reason for the seemingly confusing errors I suspect is due to the compilers inability to match your argument list to a particular method, due to the selector name being of the wrong type (string rather than selector).

This also explains the fact that when you did manage to get it to compile (as mentioned in the comments to another answer) it failed at runtime. The type checking at compile time fails to pick up this sort of error (hence the runtime exception reporting the 'unrecognized selector').

Deltics
  • 22,162
  • 2
  • 42
  • 70
  • 1
    Generally speaking you don't need to do this as it is automatically handled for you. – David Berry Sep 14 '14 at 23:50
  • Sadly, I have the exact same run-time error. It does automatically convert it to the Selector-type probably, I tried changing it to `selector: Selector("timerFunc"),` to no avail. My current code is added to the question. – Althonos Sep 14 '14 at 23:55
  • I just thought, does it matter where I have my NSTimer? Right now it's in viewDidLoad.. – Althonos Sep 15 '14 at 00:21