swift那神奇的#selector

第一章 神奇

猜猜哪個btnTapped函數(shù)會被調(diào)用础米?

import UIKit

class DemoViewController : UIViewController {
    
    override func viewDidLoad() {
        let view = DemoView()
        let btn = view.btn;
        self.view.addSubview(btn!)
    }
    
    @objc func btnTapped(_ sender: UIButton) {
        print("print: surprise!")
    }

}

class DemoView {
    var btn : UIButton!

    init() {
        btn = UIButton()
        btn.frame = CGRect(x: 110, y: 70, width: 100, height: 44)
        btn.backgroundColor = UIColor.blue
        btn.setTitle("Press me", for: .normal)
        btn.setTitle("I'm Pressed", for: .highlighted)
        btn.addTarget(self, action: #selector(DemoView.btnTapped(_:)), for: .touchUpInside)
    }
    
    @objc func btnTapped(_ sender: UIButton) {
        print("print: demo button is tapped")
    }
    
}

答案是:surprise!

第二章 解惑

正確的寫法應(yīng)該用singleton模式來實現(xiàn)DemoView,如下。

import UIKit

class DemoViewController : UIViewController {
    
    override func viewDidLoad() {
        let view = DemoView._instance
        let btn = view.btn;
        self.view.addSubview(btn!)
    }
    
    @objc func btnTapped(_ sender: UIButton) {
        print("print: surprise!")
    }

}

class DemoView {
    var btn : UIButton!

    static let _instance = DemoView()
    
    private init() {
        btn = UIButton()
        btn.frame = CGRect(x: 110, y: 70, width: 100, height: 44)
        btn.backgroundColor = UIColor.blue
        btn.setTitle("Press me", for: .normal)
        btn.setTitle("I'm Pressed", for: .highlighted)
        btn.addTarget(self, action: #selector(DemoView.btnTapped), for: .touchUpInside)
    }
    
    @objc func btnTapped(_ sender: UIButton) {
        print("print: demo button is tapped")
    }
    
}

<b>洞察:</b>

  • Selector是runtime時延遲動態(tài)綁定亏掀,#selector糖里面只是為了compiler幫助檢查prototype正確性(對以前的字符串寫法”btnTapped:”無法在編譯期檢查問題的優(yōu)化)忱反,所以即使寫成DemoView.btnTapped,也只是告訴compiler這個原型參考函數(shù)滤愕,而并非Selector在runtime時真正選取的函數(shù)温算。
    因為函數(shù)選取是在Obj-C名字空間里做,所以需要用@objc修飾需要暴露給Obj-C的函數(shù)间影。
  • addTarget的第一個參數(shù)是Obj-C消息機制的receiver對象注竿,把selector選取的函數(shù)發(fā)送給對象,其實就是“對象的方法調(diào)用”魂贬。
  • self也是運行時選取巩割,所以才會出現(xiàn)神奇的現(xiàn)象,即調(diào)用了DemoViewController而不是DemoView的btnTapped函數(shù)随橘。
    也因此,如果把上面錯誤寫法中的btn.addTarget(self改為btn.addTarget(DemoView.self锦庸,即強行要求調(diào)用DemoView對象(instance of the class)的函數(shù)机蔗,運行時點擊按鈕就會得到錯誤,unrecognized selector +[DemoView btnTapped:]甘萧。
  • BTW萝嘁,可以看到,因為swift的lazy initialization特性扬卷,所以實現(xiàn)singleton異常簡單牙言。

第三章 祛魅

Debug容易成為一門玄學(xué)。以下是國內(nèi)外網(wǎng)友分享的一些“迷信“怪得。

  • #selector選擇的類必須繼承NSObject咱枉,也就是要寫成class DemoView : NSObject
    實測:假。

  • 原型要寫成btnTapped(_:)徒恋。
    實測:假蚕断。

第四章 優(yōu)雅

通過extension Selector可以寫的更加優(yōu)雅。

import UIKit

class DemoViewController : UIViewController {
    
    override func viewDidLoad() {
        let view = DemoView._instance
        let btn = view.btn;
        self.view.addSubview(btn!)
    }
    
    @objc func btnTapped(_ sender: UIButton) {
        print("print: surprise!")
    }

}

class DemoView {
    var btn : UIButton!

    static let _instance = DemoView()
    
    private init() {
        btn = UIButton()
        btn.frame = CGRect(x: 110, y: 70, width: 100, height: 44)
        btn.backgroundColor = UIColor.blue
        btn.setTitle("Press me", for: .normal)
        btn.setTitle("I'm Pressed", for: .highlighted)
        btn.addTarget(self, action: .btnTapped, for: .touchUpInside)
    }
    
    @objc func btnTapped(_ sender: UIButton) {
        print("print: demo button is tapped")
    }
    
}

private extension Selector {
    static let btnTapped = #selector(DemoView.btnTapped)
}

<b>解讀:</b>
action:后面直接用點號的寫法是一種糖入挣,compiler看起來就是Selector.btnTapped亿乳,也正是最下方的extension代碼所實現(xiàn)的。

From painful to painless.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末径筏,一起剝皮案震驚了整個濱河市葛假,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滋恬,老刑警劉巖聊训,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異恢氯,居然都是意外死亡魔眨,警方通過查閱死者的電腦和手機媳维,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遏暴,“玉大人侄刽,你說我怎么就攤上這事∨罅梗” “怎么了州丹?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長杂彭。 經(jīng)常有香客問我墓毒,道長,這世上最難降的妖魔是什么亲怠? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任所计,我火速辦了婚禮,結(jié)果婚禮上团秽,老公的妹妹穿的比我還像新娘主胧。我一直安慰自己,他們只是感情好习勤,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布踪栋。 她就那樣靜靜地躺著,像睡著了一般图毕。 火紅的嫁衣襯著肌膚如雪夷都。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天予颤,我揣著相機與錄音囤官,去河邊找鬼。 笑死蛤虐,一個胖子當(dāng)著我的面吹牛治拿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播笆焰,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼劫谅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嚷掠?” 一聲冷哼從身側(cè)響起捏检,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎不皆,沒想到半個月后贯城,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡霹娄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年能犯,在試婚紗的時候發(fā)現(xiàn)自己被綠了鲫骗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡踩晶,死狀恐怖执泰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情渡蜻,我是刑警寧澤术吝,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站茸苇,受9級特大地震影響排苍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜学密,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一淘衙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腻暮,春花似錦彤守、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叫惊。三九已至款青,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霍狰,已是汗流浹背抡草。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蔗坯,地道東北人康震。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像宾濒,于是被迫代替她去往敵國和親腿短。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

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