10

I want to use an NSTimer in a class that doesn't inherit from UIViewVontroller. I have 2 files : a ViewController and a TimerClass like that :

ViewController:

import UIKit

class ViewController: UIViewController {

    var timerClass = TimerClass()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear(animated: Bool) {
        timerClass.launchTimer()
    }

}

TimerClass :

import Foundation

class TimerClass {

    var timer = NSTimer()

    init(){}

    func launchTimer(){
        var timer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: "timerEnd", userInfo: nil, repeats: true)
    }

    func timerEnd(){
        println("That worked")
    }
}

When I launch that app, I have a crash with :

2015-01-12 19:48:24.322 Timer_TEST[5829:185651] *** NSForwarding: warning: object 0x7fbc3be20710 of class 'Timer_TEST.TimerClass' does not implement methodSignatureForSelector: -- trouble ahead Unrecognized selector -[Timer_TEST.supportFile timerEnd]

Any idea?

Thank you

soling
  • 541
  • 6
  • 20
  • I know very little about Swift, but it's asking for a method and it's not implemented on your custom class... could you try doing so? –  Jan 12 '15 at 22:07
  • You should not use `var timer` in the function `launchTimer`, but just `timer`, because you want access to the property, right? – Michael Dorner Jan 12 '15 at 22:35

1 Answers1

29

EDIT: Note that starting in Swift 2.2 you won't be able to make this mistake! You'll use the new #selector syntax (see https://stackoverflow.com/a/35658335/341994), and the compiler won't let you form a selector for a method that isn't exposed to Objective-C.


It's merely a question of exposing the Swift function to Objective-C so that it is visible to Objective-C. You have four choices:

  • Make TimerClass descend from NSObject (and delete the init implementation):

    class TimerClass : NSObject {
    
  • Declare TimerClass with @objc [not in Swift 2.0; use the previous choice instead]:

    @objc TimerClass {
    
  • Declare the function with @objc:

    @objc func timerEnd()
    
  • Declare the function dynamic (this is probably the worst choice, as it is unnecessary - the function is not dynamic; it does not need to be altered in place by Objective-C, it just needs to be visible):

    dynamic func timerEnd(){
    
Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    It works, thanks. Any logic explanation? – Rivera Mar 31 '15 at 17:40
  • 2
    @Rivera It's just a question of permitting Objective-C to _see_ the Swift function. You have to expose it to Objective-C deliberately in some way. I've modified my answer to provide some further approaches. – matt Mar 31 '15 at 17:47
  • 1
    I would say `@objc func timerEnd()` is best because it will check that the function signature is Objective-C-compliant where `@objc TimerClass` will keep crashing otherwise. – Rivera May 28 '15 at 15:06
  • Can't make it work in generic class! This is just hell – iiFreeman Jul 01 '15 at 21:24
  • @iiFreeman That sounds interesting. I don't see your question on that topic; can you provide a link? – matt Jul 01 '15 at 21:36
  • @matt I didn't ask question, but you can try it with Swift generic class with typealias inside - it just crashes with unrecognized selector. I found a workaround by using another objc class as a target and call block on it. – iiFreeman Jul 02 '15 at 00:14
  • @iiFreeman Sorry not to see example, though. You could ask question and answer it... – matt Jul 02 '15 at 00:50
  • In Swift 2 you can't add `@objc` to a non `NSObject` subclass anymore. – Rivera Sep 25 '15 at 15:01
  • @Rivera You're exactly correct. The first two options thus collapse into one. I'll make a note in the answer. – matt Sep 25 '15 at 15:26
  • You can still use a non `NSObject` subclass' function using `@objc func`. – Rivera Sep 26 '15 at 23:42
  • @Rivera correct, that is why the third option stands as before. This is all fully spelled out at the end of this section of my book: http://www.apeth.com/swiftBook/apa.html#_selectors – matt Sep 26 '15 at 23:58