Rectangle 27 1

@selector() in Swift?


var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:Selector("logout")
)

Selectors are an internal representation of a method name in Objective-C. In Objective-C "@selector(methodName)" would convert a source-code method into a data type of SEL. Since you can't use the @selector syntax in Swift (rickster is on point there), you have to manually specify the method name as a String object directly, or by passing a String object to the Selector type. Here is an example:

Note
Rectangle 27 1

@selector() in Swift?


var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:Selector("logout")
)

Selectors are an internal representation of a method name in Objective-C. In Objective-C "@selector(methodName)" would convert a source-code method into a data type of SEL. Since you can't use the @selector syntax in Swift (rickster is on point there), you have to manually specify the method name as a String object directly, or by passing a String object to the Selector type. Here is an example:

Note
Rectangle 27 1

@selector() in Swift?


#selector
#selector(getter: MyClass.foo)
#selector(setter: MyClass.foo)
Selector
StringLiteralConvertible
let timer = Timer(timeInterval: 1, target: object,
                  selector: #selector(MyClass.test),
                  userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
                 for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
             with: button, with: otherButton)
var foo: Int
  • Multiple functions with the same base name can be differentiated by their parameter labels using the aforementioned syntax for function references (e.g. insertSubview(_:at:) vs insertSubview(_:aboveSubview:)). But if a function has no parameters, the only way to disambiguate it is to use an as cast with the function's type signature (e.g. foo as () -> () vs foo(_:)).

(This is actually an improvement over ObjC's @selector() directive, because the compiler's -Wundeclared-selector check verifies only that the named selector exists. The Swift function reference you pass to #selector checks existence, membership in a class, and type signature.)

But there are still a number of important ObjC-based APIs that use selectors, including timers and the target/action pattern. Swift provides the Selector type for working with these. (Swift automatically uses this in place of ObjC's SEL type.)

Cases where #selector doesn't work, and naming: Sometimes you don't have a function reference to make a selector with (for example, with methods dynamically registered in the ObjC runtime). In that case, you can construct a Selector from a string: e.g. Selector("dynamicMethod:") though you lose the compiler's validity checking. When you do that, you need to follow ObjC naming rules, including colons (:) for each parameter.

I'd like to mention that while "Interacting with Objective-C APIs" is on the website, it is NOT in 'The Swift Programming Language' book.

Is there anyway to add validation around passing the "selector" as a string? IE compiler warn us when we misspell, etc.

It should also be pointed out that the Cocoa frameworks expect an Objective-C style method name. If your method takes an argument you will need a ':' if it takes 2 arguments, size:andShape:, if the first argument is named you may need a With, i.e. initWithData: for func init(Data data: NSData)

Key paths: These are related to but not quite the same as selectors. There's a special syntax for these in Swift 3, too: e.g. chris.valueForKeyPath(#keyPath(Person.friends.firstName)). See SE-0062 for details. And even more KeyPath stuff in Swift 4, so make sure you're using the right KeyPath-based API instead of selectors if appropriate.

Putting a string with the function name worked, NSSelectorFromString() works also.

Remember that private symbols aren't exposed to the runtime, too your method needs to have at least internal visibility.

Selector availability: The method referenced by the selector must be exposed to the ObjC runtime. In Swift 4, every method exposed to ObjC must have its declaration prefaced with the @objc attribute. (In previous versions you got that attribute for free in some cases, but now you have to explicitly declare it.)

Swift itself doesn't use selectors several design patterns that in Objective-C make use of selectors work differently in Swift. (For example, use optional chaining on protocol types or is/as tests instead of respondsToSelector:, and use closures wherever you can instead of performSelector: for better type/memory safety.)

The great thing about this approach? A function reference is checked by the Swift compiler, so you can use the #selector expression only with class/method pairs that actually exist and are eligible for use as selectors (see "Selector availability" below). You're also free to make your function reference only as specific as you need, as per the Swift 2.2+ rules for function-type naming.

There are a couple of extra caveats for the function references you pass to the #selector expression:

This should probably mention that the selector needs a ":" at the end if it takes an argument. (E.g. test() -> "test" & test(this:String) -> "test:")

You can construct a Selector from a Swift function type using the #selector expression.

Note
Rectangle 27 1

@selector() in Swift?


var timer1 : NSTimer? = nil
timer1= NSTimer(timeInterval: 0.1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)

Change as a simple string naming in the method calling for selector syntax

Note
Rectangle 27 1

@selector() in Swift?


override func viewDidLoad() {
    super.viewDidLoad()

    var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
    self.navigationItem.rightBarButtonItem = rightButton
}

func method() {
    // Something cool here   
}

@malcomhall: @selector is handy, but it's not enforced as formally as you might think. "Undeclared selector" is merely a warning from the compiler, because new selectors can always be introduced at run time. Verifiable/refactorable selector references in Swift would be a good feature request to make, though.

Here's a quick example on how to use the Selector class on Swift:

Note that if the method passed as a string doesn't work, it will fail at runtime, not compile time, and crash your app. Be careful

When you are passing the selector string in as a variable or parameter, you'll need to let the compiler know its a selector using the Selector() function. thanks

which is horrible... is there a "NSStringFromSelector" type of thing ?

Note
Rectangle 27 1

@selector() in Swift?


func labelTapped(sender: UILabel) { }
let tapRecognizer = UITapGestureRecognizer(
            target: self,
            action: Selector("labelTapped:"))

I found many of these answers to be helpful but it wasn't clear how to do this with something that wasn't a button. I was adding a gesture recognizer to a UILabel in swift and struggled so here's what I found worked for me after reading everything above:

Note that it is public and that I am not using the Selector() syntax but it is possible to do this as well.

Where the "Selector" was declared as:

Note
Rectangle 27 1

@selector() in Swift?


var somethingToPass = "It worked"

let timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: "tester:", userInfo: somethingToPass, repeats: false)

func tester(timer: NSTimer)
{
    let theStringToPrint = timer.userInfo as String
    println(theStringToPrint)
}

@iOS-Coder just creating a timer with the initialiser does not add it to a runloop, whereas scheduledTimerWith... automatically adds it to the current runloop - so there is no strange behaviour here at all ;)

Don't worry about it, no one can be expected to read the documentation about every single method in every API ;)

I was using NSTimer(0.01, target: self, ...) which did NOT work, whereas using NSTimer.scheduledTimerWithTimeInterval(0.01, ..) DID work!? Strange but thanks @Scooter for you answer!

If you want to pass a parameter to the function from the NSTimer then here is your solution:

Include the colon in the selector text (tester:), and your parameter(s) go in userInfo.

Your function should take NSTimer as a parameter. Then just extract userInfo to get the parameter that passed.

Note
Rectangle 27 1

@selector() in Swift?


var rightBarButton = UIBarButtonItem(
    title: "Logout", 
    style: UIBarButtonItemStyle.Plain, 
    target: self, 
    action:Selector("logout")
)

Selectors are an internal representation of a method name in Objective-C. In Objective-C "@selector(methodName)" would convert a source-code method into a data type of SEL. Since you can't use the @selector syntax in Swift (rickster is on point there), you have to manually specify the method name as a String object directly, or by passing a String object to the Selector type. Here is an example:

Note
Rectangle 27 1

@selector() in Swift?


#selector
#selector(getter: MyClass.foo)
#selector(setter: MyClass.foo)
Selector
StringLiteralConvertible
let timer = Timer(timeInterval: 1, target: object,
                  selector: #selector(MyClass.test),
                  userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
                 for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
             with: button, with: otherButton)
var foo: Int
  • Multiple functions with the same base name can be differentiated by their parameter labels using the aforementioned syntax for function references (e.g. insertSubview(_:at:) vs insertSubview(_:aboveSubview:)). But if a function has no parameters, the only way to disambiguate it is to use an as cast with the function's type signature (e.g. foo as () -> () vs foo(_:)).

(This is actually an improvement over ObjC's @selector() directive, because the compiler's -Wundeclared-selector check verifies only that the named selector exists. The Swift function reference you pass to #selector checks existence, membership in a class, and type signature.)

But there are still a number of important ObjC-based APIs that use selectors, including timers and the target/action pattern. Swift provides the Selector type for working with these. (Swift automatically uses this in place of ObjC's SEL type.)

Cases where #selector doesn't work, and naming: Sometimes you don't have a function reference to make a selector with (for example, with methods dynamically registered in the ObjC runtime). In that case, you can construct a Selector from a string: e.g. Selector("dynamicMethod:") though you lose the compiler's validity checking. When you do that, you need to follow ObjC naming rules, including colons (:) for each parameter.

I'd like to mention that while "Interacting with Objective-C APIs" is on the website, it is NOT in 'The Swift Programming Language' book.

Is there anyway to add validation around passing the "selector" as a string? IE compiler warn us when we misspell, etc.

It should also be pointed out that the Cocoa frameworks expect an Objective-C style method name. If your method takes an argument you will need a ':' if it takes 2 arguments, size:andShape:, if the first argument is named you may need a With, i.e. initWithData: for func init(Data data: NSData)

Key paths: These are related to but not quite the same as selectors. There's a special syntax for these in Swift 3, too: e.g. chris.valueForKeyPath(#keyPath(Person.friends.firstName)). See SE-0062 for details. And even more KeyPath stuff in Swift 4, so make sure you're using the right KeyPath-based API instead of selectors if appropriate.

Putting a string with the function name worked, NSSelectorFromString() works also.

Remember that private symbols aren't exposed to the runtime, too your method needs to have at least internal visibility.

Selector availability: The method referenced by the selector must be exposed to the ObjC runtime. In Swift 4, every method exposed to ObjC must have its declaration prefaced with the @objc attribute. (In previous versions you got that attribute for free in some cases, but now you have to explicitly declare it.)

Swift itself doesn't use selectors several design patterns that in Objective-C make use of selectors work differently in Swift. (For example, use optional chaining on protocol types or is/as tests instead of respondsToSelector:, and use closures wherever you can instead of performSelector: for better type/memory safety.)

The great thing about this approach? A function reference is checked by the Swift compiler, so you can use the #selector expression only with class/method pairs that actually exist and are eligible for use as selectors (see "Selector availability" below). You're also free to make your function reference only as specific as you need, as per the Swift 2.2+ rules for function-type naming.

There are a couple of extra caveats for the function references you pass to the #selector expression:

This should probably mention that the selector needs a ":" at the end if it takes an argument. (E.g. test() -> "test" & test(this:String) -> "test:")

You can construct a Selector from a Swift function type using the #selector expression.

Note
Rectangle 27 1

@selector() in Swift?


#selector(keyboardDidHide(_:))
Selector("keyboardDidHide:")

Use the new #selector expression, which eliminates the need to use string literals making usage less error-prone. For reference:

Note