我有一个类,我们称之为ClassA,使用以下addTarget调用。
awesomeBtn.addTarget(nil, action: #selector(awesomeMethod), for: .touchUpInside)
当方法awesomeMethod在ClassA中时(即与addTarget调用相同的类),编译器接受上面的行。
但是,如果awesomeMethod不在ClassA中,让我们说它在ClassB中,那么编译器会抱怨并且我被迫在操作中指定类名。
awesomeBtn.addTarget(nil, action: #selector(ClassB.awesomeMethod), for: .touchUpInside)
在Swift的早期版本中(不完全确定哪个版本),我可以简单地编写以下内容,无论哪个类包含该方法。
awesomeBtn.addTarget(nil, action:("awesomeMethod"), forControlEvents:.touchUpInside)
想了解这是为什么或者我做错了什么,谢谢。
答案 0 :(得分:1)
是的,他们从String
更改了它,如果您错误地将方法名称输入到强制编译时检查方法的#selector
,那么它只是一个运行时错误。他们只是想早点找到你的错误。
但是,如果awesomeMethod不在ClassA中,让我们说它在ClassB中, 然后编译器抱怨,我被迫指定类名 在行动中。
不,您可以指定实现该方法的@objc
protocol
:
@objc protocol AwesomeProtocol {
func awesomeMethod()
}
然后,即使您的类没有实现该方法,您也可以指定:
awesomeBtn.addTarget(nil, action: #selector(AwesomeProtocol.awesomeMethod), for: .touchUpInside)
注意:任何人似乎都没有必要采用该协议。该按钮搜索响应者链并使用它找到的第一个匹配方法。虽然,您应该通过任何实现awesomeMethod
的类来采用该协议,以便Swift可以在编译时检测方法签名中的错误。
答案 1 :(得分:1)
基本上,Swift对你很好:)。
在旧版本中,您使用字符串文字或Selector(...)
语法来编写选择器。这样做的缺点是没有编译时检查选择器是否存在。如果你在某个地方有拼写错误,你只能在运行时找到它。您不需要封闭类的名称,因为选择器只是方法的名称,不包括封闭类。在运行时,按钮自己的逻辑将在您传递的target
对象中找到该选择器。没有人给出关于选择器所在类的f ** k。选择器存在于target
对象中,或者不存在。
现在Swift已经改进并提供了#selector
语法来编写选择器。 检查选择器是否有效。编译器需要查找具有相同名称的方法的声明。这就是为什么你必须添加类名,以便编译器知道在哪里寻找。否则它只会在当前类中查找它。但是,这并不意味着选择器将始终存在于运行时,因为在运行时,按钮会检查target
是否具有该选择器,因此如果您传入另一个类的选择器(不是{的类) {1}}),按钮仍无法找到选择器。