@selector()在Swift中?
我试图在Swift
创建一个NSTimer
,但我遇到了一些麻烦。
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
表达。
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:)
)来insertSubview(_:aboveSubview:)
。 但是,如果一个函数没有参数,只有这样,才能消除歧义它是使用as
投用函数的类型签名(例如foo as () -> ()
VS foo(_:)
)。 var foo: Int
,你可以使用#selector(getter: MyClass.foo)
或#selector(setter: MyClass.foo)
。 一般注意事项:
#selector
不起作用的情况,以及命名:有时,您没有使用选择器的函数引用(例如,在ObjC运行时中动态注册的方法)。 在这种情况下,你可以从一个字符串构造一个Selector
:例如Selector("dynamicMethod:")
- 尽管你失去了编译器的有效性检查。 当你这样做,你需要遵循ObjC的命名规则,包括冒号( :
)每个参数。
选择器可用性:选择器引用的方法必须暴露于ObjC运行时。 在Swift 4中,暴露给ObjC的每个方法都必须以@objc
属性作为@objc
。 (在以前的版本中,在某些情况下您可以免费获得该属性,但现在必须明确声明它。)
请记住, private
符号也不会暴露给运行时 - 您的方法至少需要internal
可见性。
关键路径:这些与选择器有关但不完全相同。 在Swift 3中也有一些特殊的语法:例如chris.valueForKeyPath(#keyPath(Person.friends.firstName))
。 详情请参阅SE-0062。 在Swift 4中还有更多KeyPath
东西,所以确保你使用了正确的基于KeyPath的API而不是选择器(如果适用的话)。
您可以在使用Cocoa和Objective-C的Swift中阅读更多关于与Objective-C API交互的选择器。
注意:在Swift 2.2之前, Selector
符合StringLiteralConvertible
,因此您可能会发现旧的代码将裸露的字符串传递给采用选择器的API。 您需要在Xcode中运行“转换为当前Swift语法”以使用#selector
。
这里有一个关于如何在Swift上使用Selector
类的简单例子:
override func viewDidLoad() {
super.viewDidLoad()
var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
self.navigationItem.rightBarButtonItem = rightButton
}
func method() {
// Something cool here
}
请注意,如果以字符串形式传递的方法不起作用,它将在运行时失败,而不是编译时间,并且会导致应用程序崩溃。 小心
另外,如果您的(Swift)类不从Objective-C类下降,那么您必须在目标方法名称字符串的末尾添加冒号,并且您必须在目标方法中使用@objc属性,例如
var rightButton = UIBarButtonItem(title: "Title", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("method"))
@objc func method() {
// Something cool here
}
否则在运行时会出现“无法识别的选择器”错误。
链接地址: http://www.djcxy.com/p/56485.html