如何為一個例項動態替換方法

Martin_wjl發表於2017-03-21

這個 Tip 來源於一道面試題,感覺很是考察知識變通的能力,對 KVO 深入瞭解的同學,應該很容易就可以答出來。這裡拋磚引玉,簡單聊聊這個 Tip

首先簡單總結下 KVO 的大概原理

  • 當你觀察一個物件時,會動態的建立該物件類的子類,這個子類重寫了被觀察屬性的 setter 方法,同時將該物件的 isa 指標指向了新建立的子類。在 Objective-C 中物件是通過 isa 指標來查詢對應類中的方法列表的,所以這裡可以把該物件看為新子類的例項物件。重寫的 setter 方法會在呼叫原 setter 方法之後,通知觀察者物件屬性值的更改。

好的,下面進入正題,聊聊如何為一個例項動態替換方法。

首先建立一個初始化工程,直接對 ViewController 進行實戰即可,在 ViewController 中加入一個 eat 方法,如下

然後寫一個 NSObject 的 Category 負責進行方法交換,將原物件的 isa 指標指向該物件類的子類(LDSubclass),並在子類中重寫 eat 方法

子類的程式碼很簡單,就是重寫 eat 方法,如果有需要,可以呼叫原方法的實現

最後在 ViewControlller 中進行測試即可,此時的 ViewController 程式碼如下

來看看列印的結果,第一個沒有 Hook 的例項,正常執行;第二個Hook 後的例項,先執行重寫的方法,後執行原方法。

原理

與 KVO 的 isa-swizzling 思路相同,對想要 Hook 例項的類建立一個子類,並在子類中重寫想要 Hook 的方法,將該例項的 isa 指標指向子類,這樣進行方法查詢時,便會在子類方法列表進行查詢,如果想要執行更多操作,可以在替換後的新方法中加入自己的邏輯。

這裡只是一個超級簡單的 Demo,很多邊界情況沒有考慮,後期可以自己完善,Demo 可以參考JYHookInstanceMethod

Reference

相關文章