36

I am switching over the syntax of my project toward Swift 2.2 (which xCode helps me do automatically); however, I do not understand the new #selector() syntax.

As an example:

timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, 
             selector: #selector(MyVC.timerCalled(_:)), //new selector syntax!
             userInfo: nil, repeats: true)

This has the selector #selector(MyVC.timerCalled(_:))

What does the _: signify? Can you add other variables into this selector? Say, #MyVC.timerCalled(_:whateverVar).

General info on what is different in this syntax as opposed to the string based implementation from earlier versions of Swift are greatly appreciated.

Marcus Leon
  • 55,199
  • 118
  • 297
  • 429
Anthony Dito
  • 3,610
  • 3
  • 29
  • 56
  • 2
    I think I explain it nicely here: http://stackoverflow.com/questions/35658334/how-do-i-resolve-ambiguous-use-of-compile-error-with-swift-selector-syntax/35658335#35658335 – matt Mar 22 '16 at 22:24
  • @matt’s Answer addresses the syntax more thoroughly, including a useful discussion of dealing with overloaded methods. – Stuart Mar 22 '16 at 22:28

4 Answers4

31

The bit in parenthesis is a mechanism for identifying the argument list for the selector that you want.

I recommend you look at the Generalized Naming proposal from Swift Evolution. It covers cases where you have a number of functions that differ only by their parameter labels and need to refer to them. The example from that document is:

extension UIView {
  func insertSubview(view: UIView, at index: Int)
  func insertSubview(view: UIView, aboveSubview siblingSubview: UIView)
  func insertSubview(view: UIView, belowSubview siblingSubview: UIView)
}

If you wanted to get a function value for one of those the result is ambiguous:

let fn = someView.insertSubview // ambiguous: could be any of the three methods

The solution implemented is to add the argument labels, without any type information to the code that generates the function value to disambiguate which you want:

let fn = someView.insertSubview(_:at:)
let fn1 = someView.insertSubview(_:aboveSubview:)

See how the labels are added in the parens?

This proposal played a role in the one that most directly applies to your question:

Referencing the Objective-C selector of a method

In this particular case the selector you want to refer to is timerCalled: which is a function of one parameter that has no label. Hence (_:). The underscore means the label is not specified and the colon.

Scott Thompson
  • 22,629
  • 4
  • 32
  • 34
19

Swift 2.2 has deprecated Stringified selectors: In swift 2.0, we use to write the selector as a String i.e "buttonClicked". The disadvantage with this approach is that the compiler can't check whether the method really exists or not at compile time(Even if you have misspelled it).

EX:1

func buttonClicked(){
}

So the above method in the new approach can be called as #selector(buttonClicked)

EX:2

func buttonClicked(stringValue : String){
}

So the above method in the new approach can be called as #selector(buttonClicked(_:))

EX:3

func buttonClicked(stringValue : String, indexValue : Int){
}

So the above method with parameters in the new approach can be called as #selector(buttonClicked(_:indexValue:))

Durga Vundavalli
  • 1,790
  • 22
  • 26
  • Hey, I have just been reading this question. Could you please briefly explain to me why the compiler would fix/change your above example to #selector(YourClass.buttonClicked) instead of just #selector(buttonClicked) when converting to swift 2.2. Is there a difference between the 2? Thank you – crashoverride777 Mar 23 '16 at 14:18
  • @crashoverride777 i think your question was explained clearly here.. http://stackoverflow.com/questions/24007650/selector-in-swift?rq=1 – Durga Vundavalli Mar 30 '16 at 01:42
  • I think you always need to prefix the method declaration with @objc – blackjacx May 18 '16 at 08:48
9

Consider below code for adding target to button in swift 3 using #selector

button.addTarget(self, action: #selector(self.buttonAction(sender:)),
                       for: UIControlEvents.touchUpInside)

 func buttonAction(sender:UIButton!){

 }

This syntax worked for me when migrating to swift 3

Ishita Sinha
  • 2,168
  • 4
  • 25
  • 38
Ankit
  • 141
  • 1
  • 3
8

This is the way Swift method signatures are represented in documentation, and it is now beginning to be used in new language features such as the #selector() syntax to express methods by their argument lists.

The each colon (:) represents a method parameter. For named parameters, the colon is preceded by the external parameter name; for unnamed parameters, an underscore (_) is used.

So for example, MyVC.timerCalled(_:)) indicates a method on the MyVC type with one unnamed parameter, which might be declared like this:

func timerCalled(timer: NSTimer) { ... }

(Note that timer is the internal parameter name, since by default the first parameter of a method is unnamed)

The type (MyVC in your example) can also be omitted if it is within the same scope of the #selector() declaration.

A more complex example might look like this:

let sel = #selector(aMethodWithSeveralParameters(_:secondParam:thirdParam:))

...

func aMethodWithSeveralParameters(firstParam: Int, secondParam: Int, thirdParam: Int) { ... }
Stuart
  • 36,683
  • 19
  • 101
  • 139