Swift中的Selector

Swift中的Selector

前言

Selector做爲一個在不少Objective-C設計模式中的重要組成部分,Swift爲了保證部分接口的一致性依然保留了這一律念。這篇文章時我在學習這部份內容時的遇到問題的一些總結。設計模式

雖然Swift中依然保留了對Selector的支持。可是在某些地方咱們能夠採用更爲安全的方式來實現Objective-C中對應的部分。例如:respondsToSelector:performSelector:能夠分別使用協議類型的可選鏈和閉包進行替換。安全

//某個協議 *respondsToSelector:*

//Objcctive-C版本 
if(self.delegate.respondsToSelector(Selector("HanggeSwiftMenuWillAnimateClose:"))){
    self.delegate.HanggeSwiftMenuWillAnimateClose(self)
}

//Swift版本
self.delegate?.HanggeSwiftMenuWillAnimateClose(self)

可是仍是不少像timer和target/action設計模式同樣的地方大量的使用了Selector。下面咱們看下這部分的處理。閉包

Swift2.2以前的狀況

在Swift2.2版本以前,selector經過一個簡單的字符串常量來傳遞。由於字符串是咱們開發人員手寫並且尚未自動補全這增長的程序出差的可能性。app

    let button = UIButton(type: .System)
    button.addTarget(self, action: Selector(「buttonTapped:」), forControlEvents: .TouchUpInside)
    ...
    func buttonTapped(sender: UIButton){ }
    
一個很好的函數命名習慣和風格就是使用控件對象的名稱做爲函數的前綴。在上面的示例中,函數名稱buttonTapped:對應的就是按鍵buttontapped事件。而且記住要傳遞惟一一個類型正確的sender參數,由於你有這個對象可是不用,老是好過你須要這個對象可是沒有要好。ide

整體上來講並非很難,可是這裏又一些問題須要咱們注意:函數

Selector的可用性:經過selector引出的方法須要暴露給ObjC運行時。若是是繼承自NSObject的類那麼就已經實現了這個特性,可是若是是純Swift的類你須要在函數的聲明前面加上@objc來進行實現。而且該函數訪問級別最起碼應該是internal,由於private是沒法暴露給運行時的。學習

Selector的名字:由於selectors是一個ObjC中的東西遵循ObjC的方法命名規則,每個參數都有一個冒號(:)。例如,名爲test()的selector就是"test",test(this: String)的selector就是"test:",test(this: String, andThat: Int)就是"test:andThat:"。this

Swift2.2中的改進

在Swift2.2中selector已經變得更加安全了。它使用#selector這種語法來實現Selector,這避免了以前使用字符串可能帶來的手動輸入錯誤。由於該語法會讓編譯器會對方法進行檢查,不存在的方法是沒法經過編譯的,這個在以前作法中是作不到的。設計

button.addTarget(self, action: #selector(ViewController.buttonTapped(_:)), forControlEvents: .TouchUpInside)

當你一眼掃過去會發現代碼比較長也不是很容易閱讀。尤爲是若是你的代碼中有不少的ViewController類型的類而且在代碼中屢次使用同一個Selector,屢次的拷貝/複製這麼長的代碼或者是修改是否是想一想就很麻煩啊?一種解決方法是:將全部Selector整理放在同一個地方,進行統一的編輯和引用。code

private struct Action {
    static let buttonTapped = 
        #selector(ViewController.buttonTapped(_:))
}
...
button.addTarget(self, action: Action.buttonTapped,       
    forControlEvents: .TouchUpInside)

咱們將全部的Selector做爲靜態常量放在Action結構裏面。這裏之因此將Action聲明爲private是爲了防止其它文件裏面也定義了一個這樣的結構致使編譯時候的重定義。

另外一種更爲語法糖一些的解決方法就是對Selector進行extension

private extension Selector {
    static let buttonTapped = 
        #selector(ViewController.buttonTapped(_:))
}
...
button.addTarget(self, action: .buttonTapped, 
    forControlEvents: .TouchUpInside)

利用語法特性,咱們不須要使用Selector.buttonTapped,從而使代碼更簡潔一些,也更裝X一些。

相關文章
相關標籤/搜索