@Swift中的选择器()?

我正在尝试在Swift中创建NSTimer,但遇到了一些问题

NSTimer(时间间隔:1,目标:self,选择器:test(),用户信息:nil,重复:true)

test()是同一类中的函数。


我在编辑器中遇到一个错误:

找不到接受所提供内容的“init”的重载
论据

当我将selector:test()更改为selector:nil时,错误消失

我试过:

  • 选择器:test()
  • 选择器:测试
  • 选择器:选择器(test())

但什么都不管用,我在参考资料中也找不到解决办法

Swift本身不使用选择器-Objective-C中使用选择器的几种设计模式在Swift中的工作方式不同。(例如,在协议类型或is/as测试中使用可选链接,而不是响应选择器:,并尽可能使用闭包,而不是性能选择器:,以提高类型/内存安全性。)

但是仍然有许多重要的基于ObjC的api使用选择器,包括计时器和目标/动作模式。Swift提供了选择器类型,用于处理这些文件。(Swift会自动使用此选项代替ObjC的SEL类型。)

在Swift 2.2(代码7.3)和更高版本(包括Swift 3/Xcode 8和Swift 4/Xcode 9)中:

您可以使用#Selector表达式从Swift函数类型构造选择器

让计时器=计时器(时间间隔:1,目标:对象,
选择器:#选择器(MyClass.test),
userInfo:nil,repeats:false)
button.addTarget(对象、操作:#选择器(MyClass.buttonTapped),
适用于:。touchUpInside)
view.perform(#选择器(UIView.insertSubview(#:上方子视图:)),
with:button,with:otherButton)

这种方法的好处是什么?函数引用由Swift编译器进行检查,因此您只能将#selector表达式与实际存在且有资格用作选择器的类/方法对一起使用(请参见下面的“选择器可用性”)。根据Swift 2.2+函数类型命名规则,您还可以根据需要自由地进行函数引用

(这实际上是对ObjC的@selector()指令的改进,因为编译器的-Wundeclared selector检查只验证指定的选择器是否存在。传递给#selector的Swift函数引用检查存在性、类中的成员资格和类型签名。)

对于传递给#selector表达式的函数引用,有几个额外的注意事项:

  • 使用上述函数引用语法(例如,insertSubview(:at:)vsinsertSubview(u:oversubview:)),可以通过参数标签区分具有相同基名称的多个函数。但是,如果函数没有参数,消除歧义的唯一方法是使用带有函数类型签名的ascast(例如fooas()->()vsfoo(:)
  • Swift 3.0+中的属性getter/setter对有一种特殊的语法。例如,给定一个var foo:Int,您可以使用选择器(getter:MyClass.foo)选择器(setter:MyClass.foo)

一般说明:

#选择器不起作用的情况下,命名:有时您没有用于创建选择器的函数引用(例如,使用在ObjC运行时动态注册的方法)。在这种情况下,您可以从字符串构造一个选择器:例如选择器(“dynamicMethod:”)——尽管您会丢失编译器的有效性检查。执行此操作时,需要遵循ObjC命名规则,包括每个参数的冒号(

选择器可用性:选择器引用的方法必须公开给ObjC运行时。在Swift 4中,暴露于ObjC的每个方法的声明必须以@ObjC属性开头。(在以前的版本中,在某些情况下可以免费获得该属性,但现在必须显式声明它。)

请记住,private符号也不会暴露于运行时-您的方法至少需要具有内部可见性

关键路径:这些路径与选择器相关,但并不完全相同。swift3中也有一种特殊的语法:例如,chris.valueForKeyPath(#keyPath(Person.friends.firstName))。详见SE-0062。Swift 4中还有更多的KeyPath内容,因此请确保您使用的是正确的基于KeyPath的API,而不是选择器(如果合适)

您可以在中使用Swift与Cocoa和Objective-C中的“与Objective-C API交互”下阅读有关选择器的更多信息

注意:在Swift 2.2之前,选择器符合StringLiteralConvertible,因此您可能会找到旧代码,其中裸字符串被传递给使用选择器的API。你会想跑的;“转换为当前Swift语法”;在Xcode中使用#选择器

发表评论