@selector 是 Objective-C 時代的一個關(guān)鍵字,它可以將一個方法轉(zhuǎn)換并賦值給一個 SEL 類型,它的表現(xiàn)很類似一個動態(tài)的函數(shù)指針韧掩。在 Objective-C 時 selector 非常常用象浑,從設(shè)定 target-action,到自舉詢問是否響應(yīng)某個方法句携,再到指定接受通知時需要調(diào)用的方法等等榔幸,都是由 selector 來負(fù)責(zé)的。在 Objective-C 里生成一個 selector 的方法一般是這個樣子的:
-(void) callMe {
//...
}
-(void) callMeWithParam:(id)obj {
//...
}
SEL someMethod = @selector(callMe);
SEL anotherMethod = @selector(callMeWithParam:);
// 或者也可以使用 NSSelectorFromString
// SEL someMethod = NSSelectorFromString(@"callMe");
// SEL anotherMethod = NSSelectorFromString(@"callMeWithParam:");
一般為了方便矮嫉,很多人會選擇使用 @selector削咆,但是如果要追求靈活的話,可能會更愿意使用 NSSelectorFromString 的版本 -- 因為我們可以在運(yùn)行時動態(tài)生成字符串蠢笋,從而通過方法的名字來調(diào)用到對應(yīng)的方法拨齐。
在 Swift 中沒有 @selector 了,取而代之昨寞,從 Swift 2.2 開始我們使用 #selector 來從暴露給 Objective-C 的代碼中獲取一個 selector瞻惋。類似地,在 Swift 里對應(yīng)原來 SEL 的類型是一個叫做 Selector 的結(jié)構(gòu)體援岩。像上面的兩個例子在 Swift 中等效的寫法是:
func callMe() {
//...
}
func callMeWithParam(obj: AnyObject!) {
//...
}
let someMethod = #selector(callMe)
let anotherMethod = #selector(callMeWithParam(_:))
和 Objective-C 時一樣歼狼,記得在 callMeWithParam 后面加上冒號 (:),這才是完整的方法名字享怀。多個參數(shù)的方法名也和原來類似羽峰,是這個樣子:
func turnByAngle(theAngle: Int, speed: Float) {
//...
}
let method = #selector(turnByAngle(_:speed:))
最后需要注意的是,selector 其實是 Objective-C runtime 的概念,如果你的 selector 對應(yīng)的方法只在 Swift 中可見的話 (也就是說它是一個 Swift 中的 private 方法)梅屉,在調(diào)用這個 selector 時你會遇到一個 unrecognized selector 錯誤:
這是錯誤代碼
private func callMe() {
//...
}
NSTimer.scheduledTimerWithTimeInterval(1, target: self,
selector:#selector(callMe), userInfo: nil, repeats: true)
正確的做法是在 private 前面加上 @objc 關(guān)鍵字值纱,這樣運(yùn)行時就能找到對應(yīng)的方法了。
@objc private func callMe() {
//...
}
NSTimer.scheduledTimerWithTimeInterval(1, target: self,
selector:#selector(callMe), userInfo: nil, repeats: true)
最后坯汤,值得一提的是计雌,如果方法名字在方法所在域內(nèi)是唯一的話,我們可以簡單地只是用方法的名字來作為 #selector 的內(nèi)容玫霎。相比于前面帶有冒號的完整的形式來說凿滤,這么寫起來會方便一些:
let someMethod = #selector(callMe)
let anotherMethod = #selector(callMeWithParam)
let method = #selector(turnByAngle)
但是,如果在同一個作用域中存在同樣名字的兩個方法庶近,即使它們的函數(shù)簽名不相同翁脆,Swift 編譯器也不允許編譯通過:
func commonFunc() {
}
func commonFunc(input: Int) -> Int {
return input
}
let method = #selector(commonFunc)
// 編譯錯誤,`commonFunc` 有歧義
對于這種問題鼻种,我們可以通過將方法進(jìn)行強(qiáng)制轉(zhuǎn)換來使用:
let method1 = #selector(commonFunc as ()->())
let method2 = #selector(commonFunc as Int->Int)