@selector
is keyword in Objective-C. It could convert a method to a SEL type, which turns out behaving as a "function pointer". In the old Objective-C‘s age, selector is widely used, from setting the target-action to introspecting. In Objective-C, the way of generating a selector would be:
-(void) callMe { //... } -(void) callMeWithParam:(id)obj { //... } SEL someMethod = @selector(callMe); SEL anotherMethod = @selector(callMeWithParam:); // Or we can use NSSelectorFromString as well // SEL someMethod = NSSelectorFromString(@"callMe"); // SEL anotherMethod = NSSelectorFromString(@"callMeWithParam:");
For writing less code, @selector
is widely used. But if we need to decide which method to call at runtime, NSSelectorFromString
would be preferred, so we could generate the method string dynamically and send the message with the name.
A bad news for selector lovers, there is no @selector
keyword anymore in Swift. Now if we aim at creating a selector, the only choice is from string. The original SEL
type is also replaced by a Selector
struct, which contains an init method. The code above in Swift should be:
func callMe() { //... } func callMeWithParam(obj: AnyObject!) { //... } let someMethod = Selector("callMe") let anotherMethod = Selector("callMeWithParam:")
Same as Objective-C, you have to add the colon (:
) following callMeWithParam
to construct the full method name. Method with multiple parameters is similar, like this:
func turnByAngle(theAngle: Int, speed: Float) { //... } let method = Selector("turnByAngle:speed:")
Besides of that, since Selector
type conforms the StringLiteralConvertible
protocol, we could even use a string to assign a selector, without using its init method explicitly. It is semantic in some situation, for example, setting a call back method when adding a notification observer:
NSNotificationCenter.defaultCenter().addObserver(self, selector: "callMe", name: "CallMeNotification", object: nil)
We should pay special attention on the fact of selector being a concept of Objective-C runtime. If the method of a selector is only exposed in Swift, but not Objective-C (or in other words, it is a private method of Swift), you might get an "unrecognized selector" exception when sending method to this selector:
One solution would be adding @objc
keyword before private
, so the runtime could get to know what you mean by the selector.
@objc private func callMe() { //... } NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector:"callMe", userInfo: nil, repeats: true)
Lastly, if the first parameter of a method has an external name, there is a convention to remember when creating a selector. We should add a with
between the method name and the initial external name. For example:
func aMethod(external paramName: AnyObject!) { ... }
To get the Selector
of this method, we should do like this:
let s = Selector("aMethodWithExternal:")