0

我有一个类,我们称它为 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)

想了解这是为什么,或者我是否做错了什么,谢谢。

4

2 回答 2

1

是的,他们将它从String如果您输入错误的方法名称只是一个运行时错误更改为#selector强制对该方法进行编译时检查。他们只是想早点发现你的错误。

但是,如果 awesomeMethod 不在 ClassA 中,假设它在 ClassB 中,那么编译器会抱怨,我不得不在操作中指定类名。

不,您可以指定一个@objc protocol实现该方法的方法:

@objc protocol AwesomeProtocol {
    func awesomeMethod()
}

然后,即使您的类没有实现该方法,您也可以指定:

awesomeBtn.addTarget(nil, action: #selector(AwesomeProtocol.awesomeMethod), for: .touchUpInside)

注意:似乎没有人需要采用该协议。该按钮向上搜索响应者链并使用它找到的第一个匹配方法。尽管如此,您应该在任何实现的类中采用该协议,awesomeMethod以便 Swift 可以在编译时检测方法签名中的错误。

于 2018-05-16T03:34:48.630 回答
1

基本上,Swift 对你很好 :)

在旧版本中,您使用字符串文字或Selector(...)语法来编写选择器。这样做的缺点是没有编译时检查选择器是否存在。如果你在某个地方有错字,你只会在运行时发现它。您不需要封闭类的名称,因为选择器只是方法的名称,不包括封闭类。target在运行时,按钮自己的逻辑将在您传递的对象中找到该选择器。没有人知道选择器在哪个类中。选择器要么存在于target对象中,要么不存在。

现在 Swift 已经改进并提供了#selector编写选择器的语法。这检查选择器是否有效。编译器需要寻找同名方法的声明。这就是为什么您必须添加类名以便编译器知道在哪里查找的原因。否则它只会在当前类中查找它。但是,这并不意味着选择器在运行时会一直存在,因为在运行时,按钮会检查 是否target有那个选择器,所以如果你传入另一​​个类的选择器(不是 的类target),按钮仍然可以'找不到选择器。

于 2018-05-16T06:06:26.840 回答