最根本的原因:
OC 是動態語言,OC 上所有方法的調用/類的生成都通過 Objective-C Runtime 在運行時進行,通過類名/方法名反射得到相應的類和方法。
分析:
1.require
在JS全局作用域上創建一個同名變量,變量指向一個對象,對象屬性 __clsName 保存類名,同時表明這個對象是一個 OC Class。
{
__clsName: "UIView"
}
2.這個JS對象調用“alloc”方法
如果這個JS對象沒有實現alloc方法,會拋異常。
初步思想:把類名傳入OC,OC 通過runtime方法找出這個類所有的方法返回給 JS,JS 類對象為每個方法名都生成一個函數,函數內容就是拿著方法名去 OC 調用相應方法。缺點:不僅要遍歷當前類的所有方法,還要循環找父類的方法直到頂層,整個繼承鏈上的所有方法都要加到JS對象上,一個類就有幾百個方法,這樣把方法全部加到 JS 對象上,碰到了挺嚴重的問題,引入幾個類就內存暴漲,無法使用。
最總思想:類似 OC 的消息轉發機制,使用 __C( ) 函數,傳入方法名,函數內部實現 將方法名和參數信息傳給 OC, OC 使用 Runtime 接口調用相應方法。
3.JS 和 OC 間的消息傳遞
OC 端啟動 JSPatch 引擎時創建的 JSContext 實例是分裝了 JavaScriptCore 框架,用于信息傳遞的對象。
4.方法替換的基礎原理
OC 每個類對象都是一個 objc_class 的結構體如下:
實現:
1.根 JS 傳過來的 類名 和 方法名 獲取類Class 和 方法選擇器SEL;
2.在類中尋找該方法獲取到 Method 對象;
3.獲取 Method 對象的 函數指針IMP 和 參數類型char;
4.新增ORIG方法函數實現指向找到的函數指針IMP(用新增方法保留原始方法實現);
5.將找到的IMP 指向 JS端實現轉成 OC 的替換方法。