当前位置: 首页 > 面试题库 >

Swift中的@selector()?

冯良才
2023-03-14
问题内容

我正在尝试创建一个NSTimerin,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())

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


问题答案:

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使用#selector表达式从Swift函数类型构造一个。

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表达式的函数引用,还有一些其他警告:

  • 使用上述函数引用语法(例如insertSubview(_:at:)vs insertSubview(_:aboveSubview:)),可以通过其参数标签来区分具有相同基本名称的多个函数。但是,如果一个函数没有参数,消除歧义的唯一方法是使用as带有该函数的类型签名的类型转换(例如foo as () -> ()vs foo(_:))。
  • Swift 3.0+中的属性getter / setter对有一种特殊的语法。例如,给定a 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中也有一种特殊的语法:eg
chris.valueForKeyPath(#keyPath(Person.friends.firstName))。有关详细信息,请参见SE-0062。还有KeyPathSwift
4中的更多内容,因此请确保您使用的是正确的基于KeyPath的API,而不是适当的选择器。

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

注意: 在Swift
2.2之前,它Selector遵循StringLiteralConvertible,因此您可能会发现旧代码,其中裸露的字符串被传递到采用选择器的API。您将需要在Xcode中运行“转换为当前的Swift语法”以使用#selector



 类似资料:
  • 问题内容: 我正在学习Swift,还有另一个问题。Swift中是否有常规的epression,如果有,我该如何使用它们? 在研究中,我发现了一些相互矛盾的信息。Apple Developer文档中 有提及RegEx的内容,但它与我见过的任何其他语言看起来都非常不同。如果这是解决方案,该如何使用? 另一方面,该网站建议RegEx在Swift中不存在。这样对吗? 如果有帮助,我尝试使用正则表达式从包含

  • 问题内容: 我正在尝试在Swift中创建字符串的HMAC SHA-1哈希,但是由于它似乎没有导入CommonCrypto框架,因此无法弄清楚如何与API进行交互。我尝试了各种不同形式的“ import CommonCrypto”并创建了一个桥接头文件,但没有一个起作用。 奇怪的是,如果我创建一个Objective-C类,那么我就可以与API交互而不会出现任何问题,因此这似乎是Swift特有的。 另

  • 问题内容: Swift当前是否支持宏,或者将来有计划添加支持吗?目前,我正在散布: 在我的代码中的各个地方。 问题答案: 在这种情况下,应为“宏”参数添加默认值。 Swift 2.2及更高版本 Swift 2.1及更低版本 这是和功能做。 除了其他答案中已经提到的条件编译之外,没有其他宏。

  • 问题内容: 我正在努力弄清楚此代码段出了什么问题。目前这在Objective- C中有效,但是在Swift中这只是在方法的第一行崩溃。它在控制台日志中显示错误消息:。 问题答案: 另请参阅马特的答案,其中包含解决方案的后半部分 让我们找到一个无需创建自定义子类或笔尖的解决方案 真正的问题在于,Swift区分可以为空()的对象和不能为空的对象。如果您没有为标识符注册笔尖,则可以返回。 这意味着我们必

  • 我一直在尝试实现一个单例,以用作我从网络上传到iOS应用程序的照片的缓存。我在下面的代码中附加了三个变体。我试图让变体2工作,但它导致一个编译器错误,我不明白,并希望得到关于我做错了什么的帮助。变体 1 执行缓存,但我不喜欢使用全局变量。变体3不做实际的缓存,我相信这是因为我在var ic = ....的分配中得到了一个副本,这是正确的吗? 任何反馈和见解将不胜感激。 谢谢,Zvi

  • 问题内容: 我在Swift中使用“ NSTimer.scheduledTimerWithTimeInterval”看到的所有示例都使用“ target:self”参数显示,但不幸的是,这在Swift Playgrounds中无法直接使用。 这是上面引用的导致错误的示例: 问题答案: 这些天您真的不应该使用。它消耗大量资源,导致不必要的电池消耗,并且该API使自己变得丑陋。 使用来代替: 当然,由于