Swift3中的 Method Swizzling


先聊聊Method Swizzling

從 Objective-C 開始, runtime一直是解決坑爹需求和面試裝逼的一大利器,然而聊起 runtime 很多人都第一個想到 Method Swizzling,.因為 Objective-C中調用方法都是動態(tài)實現(xiàn)的,當運行時的才確定到底執(zhí)行哪個方法,而 Method Swizzling 就是利用這個特點來解決很多問題.

現(xiàn)在關于 Runtime 和 Method Swizzling 的文章太多了,我推薦一篇:
神經病院Objective-C Runtime出院第三天——如何正確使用Runtime
@一縷殤流化隱半邊冰霜 大神寫的關于 runtime這幾篇,看完基本對 runtime 就沒什么問題了吧...

再看看 Swift3.0中的 Method Swizzling

先來看看 swizzling 在 Objective-C 中的注意點:(對比上文鏈接中)

1.Swizzling應該總在category的 +load中執(zhí)行 ( Objective-C )

那在 Swift 中, extension 并不是運行時加載的, 因此也沒有加載時候就會被調用的類似 +load 的方法. 事實上哗伯,Swift 實現(xiàn)的 load 并不是在 app 運行開始就被調用的惫叛〖够耍基于這些理由,我們使用另一個類初始化時會被調用的方法來進行交換:

open override static func initialize() {
    // Method Swizzling
}

這一條部分來自喵神 swiift tips 第二版, 喵神在第三版中刪除了 swizzling 這個章節(jié),理由是這部分更多是 Objective-C的內容. 我個人覺得如果在 Swift 中還需要用 Swizzling 這種技術來實現(xiàn)需求, 不如用更 Swifty的方式去解決問題, 函數(shù)式或者面向協(xié)議等等等??

2.Swizzling應該總是在dispatch_once中執(zhí)行

那么,問題來了,在3.0版本 dispatch once 已經被廢棄,這怎么辦?

剛巧的是前幾天群里的老司機 @沒故事的卓同學 寫了篇 [譯]Swift 3 中實現(xiàn)Dispatch once擴展

通過給DispatchQueue實現(xiàn)一個擴展方法來實現(xiàn) Dispatch once.
至于沒什么要 dispatch_once呢? 因為 Swizzling會改變全局狀態(tài),所以用dispatch_once來確保無論多少線程都只會被執(zhí)行一次.

3. Swift自定義類中使用 Method Swizzling

因為Method Swizzling的實現(xiàn)是基于 Objective-C 的動態(tài)派發(fā)機制,所以有兩條限制
1.包含 swizzle 方法的類需要繼承自 NSObject
2.如果要 Swizzle 的是 Swift 類型的方法的話,需要將原方法和替換方法都加上 dynamic 標記,以指明它們需要使用動態(tài)派發(fā)機制


上個 sample:

extension UIViewController {
    open override static func initialize() {
        struct Static {
            static var token = NSUUID().uuidString
        }

        if self != UIViewController.self {
            return
        }

        DispatchQueue.once(token: Static.token) { 
            let originalSelector = #selector(UIViewController.viewWillAppear(_:))
            let swizzledSelector = #selector(UIViewController.xl_viewWillAppear(animated:))

            let originalMethod = class_getInstanceMethod(self, originalSelector)
            let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

            
            //在進行 Swizzling 的時候,需要用 class_addMethod 先進行判斷一下原有類中是否有要替換方法的實現(xiàn)
            let didAddMethod: Bool = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
            //如果 class_addMethod 返回 yes,說明當前類中沒有要替換方法的實現(xiàn),所以需要在父類中查找,這時候就用到 method_getImplemetation 去獲取 class_getInstanceMethod 里面的方法實現(xiàn),然后再進行 class_replaceMethod 來實現(xiàn) Swizzing

            if didAddMethod {
                class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod)
            }
        }
    }

    func xl_viewWillAppear(animated: Bool) {
        self.xl_viewWillAppear(animated: animated)
        print("xl_viewWillAppear in swizzleMethod")
    }
}

extension DispatchQueue {
    private static var onceTracker = [String]()

    open class func once(token: String, block:() -> Void) {
        objc_sync_enter(self)
        defer { objc_sync_exit(self) }

        if onceTracker.contains(token) {
            return
        }
        
        onceTracker.append(token)
        block()
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子毫别,更是在濱河造成了極大的恐慌,老刑警劉巖典格,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岛宦,死亡現(xiàn)場離奇詭異,居然都是意外死亡耍缴,警方通過查閱死者的電腦和手機砾肺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來防嗡,“玉大人变汪,你說我怎么就攤上這事∫铣茫” “怎么了裙盾?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長他嫡。 經常有香客問我番官,道長,這世上最難降的妖魔是什么钢属? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任徘熔,我火速辦了婚禮,結果婚禮上淆党,老公的妹妹穿的比我還像新娘酷师。我一直安慰自己讶凉,他們只是感情好,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布山孔。 她就那樣靜靜地躺著懂讯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪台颠。 梳的紋絲不亂的頭發(fā)上褐望,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機與錄音蓉媳,去河邊找鬼。 笑死锅铅,一個胖子當著我的面吹牛酪呻,可吹牛的內容都是我干的。 我是一名探鬼主播盐须,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼玩荠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贼邓?” 一聲冷哼從身側響起阶冈,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎塑径,沒想到半個月后女坑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡统舀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年匆骗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片誉简。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡碉就,死狀恐怖,靈堂內的尸體忽然破棺而出闷串,到底是詐尸還是另有隱情瓮钥,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布烹吵,位于F島的核電站碉熄,受9級特大地震影響,放射性物質發(fā)生泄漏肋拔。R本人自食惡果不足惜具被,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望只损。 院中可真熱鬧一姿,春花似錦七咧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛉顽,卻和暖如春蝗砾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背携冤。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工悼粮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人曾棕。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓扣猫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親翘地。 傳聞我的和親對象是個殘疾皇子申尤,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內容

  • 轉至元數(shù)據(jù)結尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,732評論 0 9
  • 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的轉載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,569評論 33 466
  • 轉載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 736評論 0 2
  • 本文詳細整理了 Cocoa 的 Runtime 系統(tǒng)的知識衙耕,它使得 Objective-C 如虎添翼昧穿,具備了靈活的...
    lylaut閱讀 806評論 0 4
  • 1.因為你.我知道石頭剪子布的真諦 2.不喜歡背對背的擁抱.但連牽手都是一種奢侈的欲望。 3.再次來到我們一起走過...
    釦木閱讀 264評論 0 2