How many times have you had some innocuous looking code like this:
let button = UIButton(type: .InfoDark)
button.addTarget(self, action: "showInfo", forControlEvents: .TouchDown)
...which compiles without a problem but throws a runtime error when the hapless user touches the button:
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[__lldb_expr_20.SelectorDemo showInfo]: unrecognized selector
sent to instance 0x7ffb3a414ac0'
The runtime error is caused by Swift not being able find the showInfo function or maybe there is a showInfo, but it expects an argument. The root cause is, of course, the action argument of addTarget is being passed the string literal showInfo rather than a properly typed object.
Well, with Xcode 7.3 beta 4, that problem is resolved! Selectors can now be constructed from directly with the #selector expression. In practice, this means that if your code has a function that looks like this:
func showInfo(button: UIButton)
{
print("showInfo(_:)", button.debugDescription)
}We can add a target to the button with the following syntax:
let selector = #selector(showInfo(_:))
button.addTarget(self, action: selector, forControlEvents: .TouchDown)
If showInfo takes no arguments...
func showInfo()
{
print("one: showInfo()")
}
let selector = #selector(SelectorDemo.showInfo as (SelectorDemo) -> () -> ())
let selectorTwo = #selector(displayInfo(_:))
// results in:
Playground execution failed: SelectorPlayground.playground:20:37: error: use of unresolved
identifier 'displayInfo'
let selector = #selector(displayInfo(_:))
^~~~~~~~~~~
I've created a small playground to demonstrate this new feature - it obviously needs Xcode 7.3 beta 4 - which is available at my GitHub repository. Enjoy!
View comments