小编典典

Swift 中的@selector()?

all

我正在尝试创建一个NSTimer输入,Swift但我遇到了一些麻烦。

NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)

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


我在编辑器中收到错误:

找不到接受提供的参数的“init”的重载

当我更改selector: test()selector: nil错误消失。

我试过了:

  • selector: test()
  • selector: test
  • selector: Selector(test())

但是没有任何效果,我在参考文献中找不到解决方案。


阅读 124

收藏
2022-03-03

共1个答案

小编典典

Swift 本身 不使用选择器——Objective-C 中使用选择器的几种设计模式在 Swift
中的工作方式不同。(例如,在协议类型或is/as测试上使用可选链来代替respondsToSelector:,并尽可能使用闭包来代替performSelector:更好的类型/内存安全性。)

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

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

您可以使用表达式Selector从 Swift 函数类型构造 a。#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检查只验证命名选择器是否存在。传递给#selector检查存在性、类成员资格和类型签名的 Swift 函数引用。)

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

  • 使用前面提到的函数引用语法(例如insertSubview(_:at:)vs insertSubview(_:aboveSubview:)),可以通过参数标签来区分具有相同基本名称的多个函数。但是如果一个函数没有参数,消除歧义的唯一方法是使用as带有函数类型签名的强制转换(例如foo as () -> ()vs foo(_:))。
  • Swift 3.0+ 中的属性 getter/setter 对有一个特殊的语法。例如,给定一个var foo: Int,您可以使用#selector(getter: MyClass.foo)#selector(setter: MyClass.foo)

一般注意事项:

#selector 不起作用的情况和命名:有时您没有用于创建选择器的函数引用(例如,在 ObjC
运行时动态注册的方法)。在这种情况下,您可以Selector从字符串构造
a:例如Selector("dynamicMethod:"),尽管您失去了编译器的有效性检查。当您这样做时,您需要遵循 ObjC
命名规则,包括:每个参数的冒号 ( )。

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

请记住,private符号也不会暴露给运行时——您的方法至少需要具有internal可见性。

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

您可以在 Using Swift with Cocoa and Objective-C中 的与 Objective-C API
交互
下阅读有关选择器的更多信息。 __

注意: 在 Swift 2.2
之前,Selector符合StringLiteralConvertible,因此您可能会发现旧代码将裸字符串传递给采用选择器的 API。您需要在
Xcode 中运行“转换为当前 Swift 语法”以获取那些使用#selector.

2022-03-03