【iOS開發】扯淡 Method Swizzling

發表於2016-04-07

寫在前面

關於 Method Swizzling 這個東西,已經有很多高人寫了詳細的文章來介紹,我就不再班門弄斧,往深了說了。
而且不作延伸的話,這項技術本身也沒有複雜到要長文論述的地步。
本文旨在幫助不熟悉這項技術的人,開始在實際開發過程中,嘗試使用它。


這是個啥

  1. swizz 這個詞在英語裡面是“欺騙”的意思。
    Method Swizzling 也叫做“方法調配”、“方法混合”、“方法調和”,是用來互換兩個方法的實現的技巧。
  2. 這東西並不常用,比如我們用方法 A 實現了 a 這件事,方法 B 實現了 b 這件事,現在你非要用 A 實現 b,B 實現 a,即便技術上是可行的,你圖個啥?回頭再換回來你還記得不?再換第三次呢?
  3. 那麼什麼時候可能需要用到這個東西呢?除錯的時候。
    如果方法 A、B 我都知道怎麼實現的,那確實不用換。但是假如方法 A 的實現被隱藏了,那麼我是不是可以用方法 B 呼叫方法 A,再順便新增點別的功能,然後進行 A、B 實現 swizz。
    這樣再呼叫方法 A 的時候,就多了一點我們之前順便新增的功能。
    有人會說,你這有意思麼,你直接呼叫方法 B 不就得了,為啥還要換?重點在於,方法 A 如何被呼叫可能不是我們可以決定的啊。或許這個方法已經在無數個地方被呼叫了無數次,那我想批量替換的話,當然就可以 swizz 了。

舉栗子

比如說,在某個專案中,NSArray 例項的下面這個方法被呼叫了 N 多次

現在我想除錯一下,看看如果這個方法返回 true,即陣列包含我們傳入的元素的時候,這個元素在資料的什麼位置(index)。

當然直接呼叫上面這個方法就可以知道 index,但是 containsObject 被使用了太多次,Xcode 現在又不支援 Swift 重構,懶得改了。那就寫個新方法,給原方法加個可以輸出 index 的功能,再用 swizz 替換一下兩個方法的實現吧。

這裡我貼了完整的一個 demo 的程式碼,你可以直接粘到 Xcode 裡面執行。

【注意幾點】

  1. 這裡我先後呼叫了三次 containsObject 這個方法,其中第二次,它的內部實現被 myContainsObject 這個方法的內部實現替換掉了。
  2. myContainsObject 這個方法乍一看是死迴圈,如果你直接呼叫它的話,它也確實是死迴圈。但現在我們是在 RunTime 期間,動態地決定這個方法的內部實現的,在我們呼叫這個方法,進入它的函式體的時候,它的實現就已經被換掉了,所以在它的內部,你應該把 myContainsObject 這個詞在你的腦子裡換成 containsObject(如果確定此時兩個方法確實互換了實現)。

最後

如果我寫的這點東西可以幫助你以後的 debug 工作,那麼最好。
如果你要在實際專案裡用它……你要是真能用上也挺厲害。

相關文章