我正在尝试创建一个NSTimerin,Swift但是遇到了一些麻烦。
NSTimer
Swift
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test() 是同一个类中的函数。
test()
我在编辑器中遇到错误:
找不到接受提供的参数的’init’的重载
当我更改selector: test()为selector: nil错误时消失。
selector: test()
selector: nil
我试过了:
selector: test
selector: Selector(test())
但是没有任何效果,我在参考文献中找不到解决方案。
Swift 本身 不使用选择器-在Objective-C中,使用选择器的几种设计模式在Swift中的工作方式有所不同。(例如,在协议类型或is/ as测试上使用可选链接代替respondsToSelector:,并在可能的地方使用闭包代替,performSelector:以提高类型/内存的安全性。)
is
as
respondsToSelector:
performSelector:
但是仍然有许多重要的基于ObjC的API使用选择器,包括计时器和目标/操作模式。Swift提供了Selector使用这些类型的类型。(Swift自动使用它代替ObjC的SEL类型。)
Selector
SEL
您可以Selector使用#selector表达式从Swift函数类型构造一个。
#selector
let timer = Timer(timeInterval: 1, target: object, selector: #selector(MyClass.test), userInfo: nil, repeats: false) button.addTarget(object, action: #selector(MyClass.buttonTapped), for: .touchUpInside) view.perform(#selector(UIView.insertSubview(_:aboveSubview:)), with: button, with: otherButton)
这种方法的好处是什么?Swift编译器会检查函数引用,因此您只能将#selector表达式与实际存在且有资格用作选择器的类/方法对一起使用(请参见下面的“选择器可用性”)。您还可以根据功能类型命名的Swift 2.2+规则,随意根据需要指定功能。
(这实际上是对ObjC @selector()指令的改进,因为编译器的-Wundeclared- selector检查仅验证命名选择器是否存在。传递给您的Swift函数引用将#selector检查是否存在,类的成员身份和类型签名。)
@selector()
-Wundeclared- selector
对于传递给#selector表达式的函数引用,还有一些其他警告:
insertSubview(_:at:)
insertSubview(_:aboveSubview:)
foo as () -> ()
foo(_:)
var foo: Int
#selector(getter: MyClass.foo)
#selector(setter: MyClass.foo)
情况下#selector无法正常工作,并命名:有时候你没有一个函数的引用,使一个选择器(例如,用在ObjC运行时动态注册的方法)。在这种情况下,您可以Selector从字符串构造a :例如Selector("dynamicMethod:")-尽管您丢失了编译器的有效性检查。执行此操作时,需要遵循ObjC命名规则,包括:每个参数的冒号()。
Selector("dynamicMethod:")
:
选择器可用性:选择器 引用的方法必须公开给ObjC运行时。在Swift 4中,每个公开给ObjC的方法都必须在其声明的前面加上@objc属性。(在以前的版本中,某些情况下您可以免费获得该属性,但是现在您必须显式声明它。)
@objc
请记住,private符号也不会暴露给运行时-您的方法至少需要具有internal可见性。
private
internal
关键路径: 这些 路径 与选择器相关,但并不完全相同。Swift 3中也有一种特殊的语法:eg chris.valueForKeyPath(#keyPath(Person.friends.firstName))。有关详细信息,请参见SE-0062。还有KeyPathSwift 4中的更多内容,因此请确保您使用的是正确的基于KeyPath的API,而不是适当的选择器。
chris.valueForKeyPath(#keyPath(Person.friends.firstName))
KeyPath
您可以在“ 将Swift与Cocoa和Objective-C结合使用”中的“ 与Objective-C API交互”下阅读有关选择器的更多信息。 __
注意: 在Swift 2.2之前,它Selector遵循StringLiteralConvertible,因此您可能会发现旧代码,其中裸露的字符串被传递到采用选择器的API。您将需要在Xcode中运行“转换为当前的Swift语法”以使用#selector。
StringLiteralConvertible