上一篇文章說起到了AOP的概念和一些應用例子,以及SFAspect是基於消息轉發實現AOP的,這一篇文章主要是講述SFAspect的實現原理緩存
SFAspect是基於runtime中的消息轉發去實現的,由於runtime的知識點涉及到比較多,這裏放在另外的文章去分析markdown
在iOS runtime中說明了像OC中面向對象的基礎,和消息發送機制的概述流程函數
在objc庫源碼分析(3)-方法調用-消息發送 和 objc庫源碼分析(3)-方法調用-消息轉發 中,從objc源碼中詳細分析了消息發送和消息轉發的詳細流程源碼分析
Objective-c中的函數調用實際上是轉換成objc_msgSend系列的函數調用,也就是消息發送,post
調用objc_msgSend()時會傳入接受對象target和方法名稱sel以及參數。在objc_msgSend函數回去查找方法緩存,看類的緩存是否存在方法sel對應的方法實現IMP。若是找不到,就會執行lookUpImpOrForward()方法去查找sel對應的IMP.spa
在lookUpImpOrForward()中會去查找方法的IMP,若是找不到,就會進入到動態解析過程,若是仍是找不到方法實現,就會將該sel對應的IMP設置爲_objc_msgForward,並存入到方法的緩存中。將IMP設置爲forward_imp,也就是說方法調用即將進入消息轉發流程。指針
消息轉發過程當中有兩個步驟 1 查找替代執行的對象,也就會調用forwardingTargetForSelector方法 2 若是找不到替代執行的對象,則會內部消化,調用methodSignatureForSelector獲取方法簽名和調用forwardInvocation執行自定義操做code
SFAspect的實現正是經過將被調用方法的sel對應的IMP設置爲_objc_msgForward,讓調用方法進入消息轉發流程,並在自定義的methodSignatureForSelector和forwardInvocation中進行自定義的操做去實現AOP功能。以下圖orm
經過方法交換的方法去實現爲類添加自定義methodSignatureForSelector和forwardInvocation方法,而後在自定義的forwardInvocation執行咱們須要的操做,去實現OC中的Hook。對象
上面提到,會在自定義的forwardInvocation執行咱們須要的操做,那如何在forwardInvocation中執行自定義的操做呢?
首先調用hookSel或hookAllClassSel的時候,咱們會把hookSel和hookAllClassSel裏面的內容(被hook的對象,hook的ID,優先級,sel以及操做block)包裝成一個SFAspectModel對象
將SFAspectModel對象添加到被hook對象的SFAspectContainer中,SFAspectContainer 是一個管理被hook對象全部的hook內容的容器類。SFAspectContainer是經過動態綁定objc_setAssociatedObject綁定到對象的類中(若是對象是實例,則綁定到類中,若是對象是類,則綁定到類對應的元類中)
當調用hook方法的時候,進入到消息轉發流程,執行自定義的forwardInvocation的時候。在自定義的forwardInvocation中取出被hook對象的SFAspectContainer容器,拿到容器中的SFAspectModel對象,取出SFAspectModel對象的操做block
上面的三個步驟關係以下圖所示
經過強制使方法調用進入消息轉發和上述操做步驟後,就能夠實現Hook一個方法了。
在SFAspect中能夠經過hookAllSel去hook一個類全部實例的對象,也能夠經過hookSel去hook一個對象。
SFAspect中能夠經過調用SFAspectModel的stop方法中止後續操做,其實實現的方式也特別簡單,就是經過拋出異常去實現的。當咱們對方法進行hook的時候,沒進行一個hook操做都會用try catch去捕獲異常,以下圖所示
在調用stop函數時,就會拋出一個Error,當catch到這個error的時候,就會退出forwardInvocation函數
當咱們調用removeHook方法的時候,會在對象的類的SFAspectContainer中檢查是否有該sel的hook對象SFAspectModel,若是有,則刪除。 當SFAspectContainer爲空的時候,就會銷燬SFAspectContainer。並同時重置被hook的方法,methodSignatureForSelector和forwardInvocation方法,
文章中有些細節沒有提價到,如hook優先級的控制,動態生成子類的釋放,鎖操做等 代碼很少,若是感興趣的童鞋能夠下載源碼看一下