Selector

@selector 是 Objective-C 時(shí)代的一個(gè)關(guān)鍵字,它可以將一個(gè)方法轉(zhuǎn)換并賦值給一個(gè) SEL 類(lèi)型,它的表現(xiàn)很類(lèi)似一個(gè)動(dòng)態(tài)的函數(shù)指針。在 Objective-C 時(shí) selector 非常常用,從設(shè)定 target-action,到自舉詢(xún)問(wèn)是否響應(yīng)某個(gè)方法,再到指定接受通知時(shí)需要調(diào)用的方法等等,都是由 selector 來(lái)負(fù)責(zé)的。在 Objective-C 里生成一個(gè) selector 的方法一般是這個(gè)樣子的:

-(void) callMe {
    //...
}

-(void) callMeWithParam:(id)obj {
    //...
}

SEL someMethod = @selector(callMe);
SEL anotherMethod = @selector(callMeWithParam:);

// 或者也可以使用 NSSelectorFromString
// SEL someMethod = NSSelectorFromString(@"callMe");
// SEL anotherMethod = NSSelectorFromString(@"callMeWithParam:");

一般為了方便,很多人會(huì)選擇使用 @selector,但是如果要追求靈活的話,可能會(huì)更愿意使用 NSSelectorFromString 的版本 -- 因?yàn)槲覀兛梢栽谶\(yùn)行時(shí)動(dòng)態(tài)生成字符串,從而通過(guò)方法的名字來(lái)調(diào)用到對(duì)應(yīng)的方法。
在 Swift 中沒(méi)有 @selector 了,取而代之,從 Swift 2.2 開(kāi)始我們使用 #selector 來(lái)從暴露給 Objective-C 的代碼中獲取一個(gè) selector。類(lèi)似地,在 Swift 里對(duì)應(yīng)原來(lái) SEL 的類(lèi)型是一個(gè)叫做 Selector 的結(jié)構(gòu)體。像上面的兩個(gè)例子在 Swift 中等效的寫(xiě)法是:

func callMe() {
    //...
}

func callMeWithParam(obj: AnyObject!) {
    //...
}

let someMethod = #selector(callMe)
let anotherMethod = #selector(callMeWithParam(_:))

和 Objective-C 時(shí)一樣,記得在 callMeWithParam 后面加上冒號(hào) (:),這才是完整的方法名字。多個(gè)參數(shù)的方法名也和原來(lái)類(lèi)似,是這個(gè)樣子:

func turnByAngle(theAngle: Int, speed: Float) {
    //...
}

let method = #selector(turnByAngle(_:speed:))

最后需要注意的是,selector 其實(shí)是 Objective-C runtime 的概念,如果你的 selector 對(duì)應(yīng)的方法只在 Swift 中可見(jiàn)的話 (也就是說(shuō)它是一個(gè) Swift 中的 private 方法),在調(diào)用這個(gè) selector 時(shí)你會(huì)遇到一個(gè) unrecognized selector 錯(cuò)誤:
這是錯(cuò)誤代碼

private func callMe() {
     //...
}

NSTimer.scheduledTimerWithTimeInterval(1, target: self,
            selector:#selector(callMe), userInfo: nil, repeats: true)

正確的做法是在 private 前面加上 @objc 關(guān)鍵字,這樣運(yùn)行時(shí)就能找到對(duì)應(yīng)的方法了。

@objc private func callMe() {
    //...
}

NSTimer.scheduledTimerWithTimeInterval(1, target: self,
             selector:#selector(callMe), userInfo: nil, repeats: true)

最后,值得一提的是,如果方法名字在方法所在域內(nèi)是唯一的話,我們可以簡(jiǎn)單地只是用方法的名字來(lái)作為 #selector 的內(nèi)容。相比于前面帶有冒號(hào)的完整的形式來(lái)說(shuō),這么寫(xiě)起來(lái)會(huì)方便一些:

let someMethod = #selector(callMe)
let anotherMethod = #selector(callMeWithParam)
let method = #selector(turnByAngle)

但是,如果在同一個(gè)作用域中存在同樣名字的兩個(gè)方法,即使它們的函數(shù)簽名不相同,Swift 編譯器也不允許編譯通過(guò):

func commonFunc() {

}

func commonFunc(input: Int) -> Int {
    return input
}

let method = #selector(commonFunc)
// 編譯錯(cuò)誤,`commonFunc` 有歧義

對(duì)于這種問(wèn)題,我們可以通過(guò)將方法進(jìn)行強(qiáng)制轉(zhuǎn)換來(lái)使用:

let method1 = #selector(commonFunc as ()->())
let method2 = #selector(commonFunc as Int->Int)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,767評(píng)論 0 9
  • 之前去XXXX公司面試被問(wèn)到“怎樣使用performSelector傳入3個(gè)以上參數(shù),其中一個(gè)為結(jié)構(gòu)體?”當(dāng)時(shí)年少...
    Miu七七閱讀 7,811評(píng)論 2 16
  • 轉(zhuǎn)自原文鏈接 @selector是 Objective-C 時(shí)代的一個(gè)關(guān)鍵字,它可以將一個(gè)方法轉(zhuǎn)換并賦值給一個(gè)SE...
    Zakerberg閱讀 662評(píng)論 0 0
  • 由于種種原因,簡(jiǎn)書(shū)等第三方平臺(tái)博客不再保證能夠同步更新,歡迎移步 GitHub:https://github.co...
    萌面大道閱讀 36,093評(píng)論 19 30
  • 三張數(shù)據(jù)表關(guān)系如圖: 其實(shí)出現(xiàn)表循環(huán)依賴(lài)情況:就是 同時(shí) ConfigCompany和 Department 也...
    萬(wàn)惡的Nickey閱讀 1,296評(píng)論 0 0