You cannot use generic functions as targets for the selector string literals. Why? The selectors contain no information about the argument type of their targets, only:
- The name of of the target for the selector (method name),
- and, (implicitly) the number of arguments for the target of the selector.
In so, Swift wont even allow non-generic functions with same name and same number of arguments to be used as targets for selectors, since there will be a conflict w.r.t. which target the selector should make use of.
E.g., consider the following (playground) example:
class Foo : UIView {
var button = UIButton()
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
button.addTarget(self, action: "eventFired:", forControlEvents: UIControlEvents.TouchUpInside)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func eventFired(sender: UIButton){
print("event fired!")
}
}
let foo = Foo()
foo.button.sendActionsForControlEvents(.TouchUpInside)
/* event fired! */
This works as intended, but now try adding the following method to the Foo
class:
class Foo : UIView {
// ...
func eventFired(nothingToDoWithAButton: Int){
print("another event fired!")
}
}
The same example as above now yields an error, as the selector is in conflict as to which target method to call.
let foo = Foo()
foo.button.sendActionsForControlEvents(.TouchUpInside)
/* error ... */
error: method 'eventFired
' with Objective-C selector 'eventFired:
'
conflicts with previous declaration with the same Objective-C selector ...
We finally note that if we change the above additional method into
class Foo : UIView {
// ...
func eventFired(nothingToDoWithAButton: Int, someBool: Bool){
print("another event fired!")
}
}
Then the selector finds, as expected, its target eventFired(:UIButton)
as it can differ between the two eventFired
methods due to the difference in number of arguments.
From the above, it's obvious that selectors/selector literals, in their current form, are too primitive to be able to use, and identify, unequivocally, generic targets. The selectors would need to include target argument type knowledge to be able to differ between same-name/same-number-of-arguments targets.
Finally note that selectors, in their current form as string literals, will be deprecated in Swift 2.2, and removed in Swift 3.0, in favour of a new expression syntax #selector
, see:
(Edit addition w.r.t. OP:s comment below)
You could try to mimic a somewhat generic selector target by letting the target catch various signals from reference types (...(:AnyObject)
), and handle the event depending on which type that is wrapped in the AnyObject
argument:
class Foo : UIView {
var button = UIButton()
var sw = UISwitch()
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
button.addTarget(self, action: "eventFired:", forControlEvents: .TouchUpInside)
sw.addTarget(self, action: "eventFired:", forControlEvents: .ValueChanged)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func eventFired(sender: AnyObject){
switch(sender) {
case is UIButton: print("button event fired!")
case is UISwitch: print("switch event fired!")
case _: print("unknown event fired")
}
}
}
let foo = Foo()
foo.button.sendActionsForControlEvents(.TouchUpInside)
/* button event fired! */
foo.sw.sendActionsForControlEvents(.ValueChanged)
/* switch event fired! */