47

I've been using selectors for a while, and even after migrating to Swift I was able to use them without issues. That's how I was using on Swift 2 without issues until I updated Xcode to version 7.3:

enter image description here

As use can see I use selectors with NSTimer.

This is the action that is called:

 func Start () {

 }

As you can see Xcode 7.3 now gives a warning "No method declared with Objective-C selector". By clicking on the warning, Xcode offers a quick fix to the code by adding "Selector", but then I still get the same warning:enter image description here

Nakilon
  • 34,866
  • 14
  • 107
  • 142
tomDev
  • 5,620
  • 5
  • 29
  • 39

4 Answers4

92

Since Swift 2.2 / Xcode 7.3 there is a new way to use a selector: Selector("funcName") was changed to #selector(ClassName.funcName)

Have a look at https://github.com/apple/swift-evolution/blob/master/proposals/0022-objc-selectors.md ,

tl;dr;

Replace Selector("Start") with #selector(YOUR_CLASS.Start)

where YOUR_CLASS = class of target in given context.

If you don't want to do it manually, Xcode provides easy fix itself by default, when you have the following situation, tap on the Yellow triangles ( sometimes required to tap/click multiple times ),

enter image description here

it will give you suggestion: enter image description here

And if you select that suggestion, it will automatically update the selector: enter image description here

ogres
  • 3,660
  • 1
  • 17
  • 16
  • Thanks! This works without issues: NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(ViewController.Start), userInfo: nil, repeats: false) – tomDev Mar 22 '16 at 18:42
  • 2
    It is so much better this way, no more crashes due to typos – crashoverride777 Mar 22 '16 at 19:19
  • Thanks for the link. I read "Syntactically, @selector(method reference) would match Objective-C more closely, but it doesn't make sense in Swift where @ always refers to attributes." Do they mean annotations instead? – John Difool Mar 23 '16 at 04:40
  • @crashoverride777 sure, but the obj-c and swift compilers already warn about unknown selectors which is generally enough to avoid the problem. – nielsbot Mar 24 '16 at 04:25
  • 1
    Not sure what you mean? Before swift 2.2 selectors were typed as strings so you got no compiler warning if you mistyped. – crashoverride777 Mar 24 '16 at 11:31
  • 1
    Worth noting, since it looks like this question might be linked to often, that method names typically begin with a lowercase letter, so `func Start` and `YOUR_CLASS.Start` should be `func start` and `YOUR_CLASS.start`. – Aaron Brager Mar 25 '16 at 03:22
  • 1
    @crashoverride777:what I need to do if same method is using in two different classes?? – Donal Apr 07 '16 at 07:52
  • 1
    Is it possible to pass parameters using this method? – Dave G May 07 '16 at 01:32
4

Both following statements work perfectly. The upper one is mostly used. However when the selector method is in a different ViewController the compiler warning "No method declared with Objective-C selector 'buttonHandler'" may occur.

The second listed statement does not give this warning.

button.addTarget(parentViewController, action: Selector("buttonHandler:"), forControlEvents: .TouchUpInside)

button.addTarget(parentViewController, action: #selector(MainViewController.buttonHandler), forControlEvents: .TouchUpInside)

In the target view controller (MainViewController) you can define the module:

func buttonHandler(sender:UIButton!) {
    print ("Pressed")
}
Vincent
  • 4,342
  • 1
  • 38
  • 37
  • Although it gives a warning, it will work. Just tested on Apple Swift version 2.2. Note the ':' which is required. – Vincent Mar 25 '16 at 12:52
2

On Swift 4 I had to add @objc before the func to get rid of the warnings.

This is how I call the func with NSTimer:

 Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.intro), userInfo: nil, repeats: false)

This is how the func is declared:

     @objc func intro () {

          // do your stuff here         

     }

I also updated the setting as the Xcode requested:

enter image description here

No more warnings, everything seems to be working fine.

tomDev
  • 5,620
  • 5
  • 29
  • 39
0

Some findings of my own to support what Vincent said (too long to be a direct comment)

It's not necessarily in a different view controller, but just a different file where the following format won't work:

button.addTarget(parentViewController, action: Selector("buttonHandler:"), forControlEvents: .TouchUpInside)

For instance, if you have an extension in a separate file, although for the same view controller, this format Selector("buttonHandler:") won't work.

Further, when the selector is in the same file and VC, Xcode's quick-fix prompts you to have the selector include the constructor, so it would look something like this:

#selector(MainViewController.buttonHandler(_:))

However this format only works when the selector is in the same VC + file, if it is in a separate file, but same VC, then that recommended method won't work, and you need to use the method without the constructor

#selector(MainViewController.buttonHandler)

EricK
  • 71
  • 1
  • 4