我正在尝试创建一个 NSTimer
在 Swift
但我遇到了一些麻烦。
NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)
test()
是同一个类中的函数。我在编辑器中收到错误消息:
Could not find an overload for 'init' that accepts the supplied arguments
当我改变
selector: test()
至 selector: nil
错误消失。我试过了:
selector: test()
selector: test
selector: Selector(test())
但是没有任何效果,我在引用文献中找不到解决方案。
最佳答案
Swift 本身不使用选择器——Objective-C 中使用选择器的几种设计模式在 Swift 中的工作方式不同。 (例如,在协议(protocol)类型上使用可选链或 is
/as
测试而不是 respondsToSelector:
,并尽可能使用闭包而不是 performSelector:
以获得更好的类型/内存安全。)
但是仍然有许多重要的基于 ObjC 的 API 使用选择器,包括计时器和目标/ Action 模式。 Swift 提供了 Selector
用于处理这些的类型。 (Swift 自动使用它来代替 ObjC 的 SEL
类型。)
在 Swift 2.2 (Xcode 7.3) 及更高版本(包括 Swift 3/Xcode 8 和 Swift 4/Xcode 9)中:
您可以构建一个 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
表达式仅用于实际存在且有资格用作选择器的类/方法对(请参阅下面的“选择器可用性”)。您还可以根据 the Swift 2.2+ rules for function-type naming 自由地根据需要指定函数引用。 .(这实际上是对 ObjC 的
@selector()
指令的改进,因为编译器的 -Wundeclared-selector
检查仅验证命名选择器是否存在。传递给 #selector
的 Swift 函数引用检查是否存在、类中的成员身份和类型签名。 )对于传递给
#selector
的函数引用,还有一些额外的警告。表达:insertSubview(_:at:)
与 insertSubview(_:aboveSubview:)
)。但是如果一个函数没有参数,唯一的消除歧义的方法是使用 as
使用函数的类型签名进行转换(例如 foo as () -> ()
与 foo(_:)
)。 var foo: Int
,您可以使用 #selector(getter: MyClass.foo)
或 #selector(setter: MyClass.foo)
. 一般注意事项:
#selector
的情况不起作用,并命名:有时您没有函数引用来创建选择器(例如,使用在 ObjC 运行时中动态注册的方法)。在这种情况下,您可以构造一个 Selector
来自字符串:例如Selector("dynamicMethod:")
——虽然你失去了编译器的有效性检查。这样做时,您需要遵循 ObjC 命名规则,包括每个参数的冒号 ( :
)。选择器可用性:选择器引用的方法必须暴露给 ObjC 运行时。在 Swift 4 中,每个暴露给 ObjC 的方法都必须以
@objc
开头的声明。属性。 (在以前的版本中,您在某些情况下可以免费获得该属性,但现在您必须明确声明它。)请记住
private
符号也不会暴露给运行时——你的方法至少需要有 internal
能见度。关键路径:这些与选择器相关但并不完全相同。在 Swift 3 中也有一个特殊的语法:例如
chris.valueForKeyPath(#keyPath(Person.friends.firstName))
.见 SE-0062详情。甚至更多 KeyPath
stuff in Swift 4 ,因此请确保在适当的情况下使用正确的基于 KeyPath 的 API 而不是选择器。您可以在 Interacting with Objective-C APIs 下阅读有关选择器的更多信息在将 Swift 与 Cocoa 和 Objective-C 结合使用。
注:在 Swift 2.2 之前,
Selector
符合 StringLiteralConvertible
,因此您可能会发现旧代码将裸字符串传递给采用选择器的 API。您需要在 Xcode 中运行“Convert to Current Swift Syntax”以获得使用 #selector
的那些。 .
关于swift - @selector() 在 Swift 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24007650/