Swift itself不使用 Select 器——Objective-C中使用 Select 器的几种设计模式在Swift中的工作方式不同.(例如,在协议类型或is
/as
测试上使用可选链接,而不是respondsToSelector:
,并尽可能使用闭包,而不是performSelector:
,以提高类型/内存安全性.)
但仍有许多重要的基于ObjC的API使用 Select 器,包括计时器和目标/动作模式.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
表达式与实际存在且有资格用作 Select 器的类/方法对一起使用(请参阅下面的" Select 器可用性").您还可以根据需要自由地进行函数引用,具体到the Swift 2.2+ rules for function-type naming.
(这实际上是对ObjC的@selector()
指令的改进,因为编译器的-Wundeclared-selector
判断只验证指定的 Select 器是否存在.传递给#selector
的Swift函数引用判断存在性、类中的成员资格和类型签名.)
对于传递给#selector
表达式的函数引用,还有几个额外的注意事项:
- 使用上述syntax for function references(例如
insertSubview(_:at:)
vs insertSubview(_:aboveSubview:)
),可以通过参数标签区分具有相同基本名称的多个函数.但是如果一个函数没有参数,消除歧义的唯一方法是使用带有函数类型签名的as
强制转换(例如foo as () -> ()
vs foo(_:)
).
- Swift 3.0+中的属性getter/setter对有一种特殊的语法.例如,你可以使用
#selector(setter: MyClass.foo)
.
一般说明:
Cases where 100 doesn't work, and naming:有时,您没有函数引用来创建 Select 器(例如,在ObjC运行时动态注册的方法).在这种情况下,你可以从一个字符串中构造一个Selector
:例如Selector("dynamicMethod:")
——尽管你失go 了编译器的有效性判断.这样做时,需要遵循ObjC命名规则,包括每个参数的冒号(:
).
Selector availability: Select 器引用的方法必须公开给ObjC运行时.在Swift 4中,expose 于ObjC的每个方法的声明必须以@objc
属性开头.(在以前的版本中,在某些情况下可以免费获得该属性,但现在必须显式声明它.)
记住,private
个符号也不会expose 在运行时中——您的方法需要至少有internal
个可见性.
Key paths:这些与 Select 器有关,但并不完全相同.Swift 3中也有一个特殊的语法:例如chris.valueForKeyPath(#keyPath(Person.friends.firstName))
.详情见SE-0062.更重要的是,如果合适的话,请确保使用正确的基于键路径的API,而不是 Select 器.
你可以在Using Swift with Cocoa and Objective-C中阅读更多关于Interacting with Objective-C APIs以下 Select 器的信息.
Note: Swift 2.2之前,Selector
符合StringLiteralConvertible
,所以您可能会发现旧代码,其中裸字符串被传递给使用 Select 器的API.您需要在Xcode中运行"Convert to Current Swift Syntax",以获得使用#selector
的语法