您不能将通用函数作为选择器字符串文字的目标。为什么呢?因为选择器不包含关于其目标参数类型的信息,只包括:
- 选择器目标的名称(方法名称)
- 以及(隐式地)选择器目标的参数数量。
因此,即使是具有相同名称和相同参数数量的非通用函数,Swift也不允许将其用作选择器的目标,因为这会导致选择器无法确定使用哪个目标。
例如,考虑以下(playground)示例:
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)
这个功能按预期工作,但现在尝试向
Foo
类添加以下方法:
class Foo : UIView {
func eventFired(nothingToDoWithAButton: Int){
print("another event fired!")
}
}
与上面相同的示例现在会产生错误,因为选择器在调用哪个目标方法方面存在冲突。
let foo = Foo()
foo.button.sendActionsForControlEvents(.TouchUpInside)
/* error ... */
错误:方法'eventFired
'与Objective-C选择器'eventFired:
'的先前声明冲突...
最后我们注意,如果我们将上述附加方法更改为
class Foo : UIView {
func eventFired(nothingToDoWithAButton: Int, someBool: Bool){
print("another event fired!")
}
}
然后选择器按预期找到了其目标
eventFired(:UIButton)
,因为它可以根据参数数量的不同区分两个
eventFired
方法。
从上面可以看出,选择器/选择器文字在它们当前的形式下太过原始,无法明确地识别和使用通用目标。这些选择器需要包括目标参数类型知识才能区分同名/同参数数量的目标。
最后请注意,选择器在Swift 2.2中将作为字符串文字被弃用,并在Swift 3.0中被移除,以支持新的表达式语法
#selector
,请参见:
(根据原帖下面的评论进行编辑)
您可以尝试通过让目标捕获来自参考类型的各种信号(...(:AnyObject)
),并根据包含在AnyObject
参数中的类型来处理事件,从而模仿某种通用选择器目标:
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)
foo.sw.sendActionsForControlEvents(.ValueChanged)