TTPatch開發問題記錄

TTPatch

熱修復、熱更新、JS代碼動態下發、動態創建類

https://github.com/yangyangFeng/TTPatch


關係方法註冊和方法覆蓋設計方案

  • Oc 不存在的方法,無需註冊到Oc中,只在Js端保留方法信息,供Js端代碼直接調用
  • Oc 已存在方法,需要先獲取 original IMP,將原方法 IMP 替換成我們的消息轉發,然後重新添加一個以 original IMP 爲實現,*** 爲前綴的新方法。

JS中聲明Oc中的Class設計方案

首先我們要搞清楚JS中引入新Class

1、Class能被識別(非undefined)
2、Class能調用方法

第一步讓我們看看怎麼做,如何讓Oc Class能被JS識別呢?

我們可以將Oc Class註冊到global中,這樣我們的Class就能被JS識別,而不是undefined類型.

Class能識別了,那麼在JS中如何才能調用Oc的方法而不報錯呢?

這個問題其實很簡單,我的解決方案將 impoet Class包裝成類似於NSObjectJSObject

class JSObject {
    constructor(className,instance) {
        this.__isa = instance ? instance : null;
        this.__metaIsa;
        this.__className = className;
        this.__isInstance = instance ? true : false;
    }
}

這樣子的,JSObject作爲操作對象就使我們接下來的方法調用變得可行。
因爲如果以String的方式存到global中是不合理,首先當前調用者的信息我們無法全部保存,然後就是String如何像對象一樣調用方法,所以看上去這是唯一可行的方案。

現在知道了我們所有的對象都是JSObject,下面看一段實際場景下的JS代碼

UIView.call('alloc').call('initWithFrame:',new TTReact(120,100,100,100))

相信瞭解JS的人心裏已經有了答案,其實我們只需要給JSObject 添加一個call()方法,這樣所有的方法調用都經由call()方法做發送處理.

我之前看過JSPatch的使用文檔,貼上一段代碼:

UIView.alloc().init()

很好奇他是怎麼做的,竟然可以在JS端調用Oc的方法.實現這個功能的方法是把所有的Oc方法註冊到 JSObject 中,但是瞭解iOS的開發者知道,這是不友好的,任何一個class的繼承關係都是很複雜的,感覺不是一個很小的工作。
所以這也是我沒有像JSPatch這麼寫的原因。

但是,可但是其實不是這樣子的,JSPatch並不是真的可以在JS中調用Oc方法,他其實在Native端加載前做了轉換,將

UIView.alloc().init()

轉成了

UIView.c('alloc').().c('init').()

大概就是這樣吧,畢竟我是要自己寫一套熱更新機制,所以沒有過多的看JSPatch具體實現,只是拿來和我的方案做比較,如何做更適合。

Commit問題記錄

1.內存問題

解決方式 使用 __unsafe_unretained 修飾臨時變量,防止 strong修飾的臨時變量在局部方法結束時隱式調用 release,導致出現殭屍對象

2.Oc調用js方法,多參數傳遞問題

這裏面利用arguments和js中的apply,就可以以多參數調用,而不是一個爲數組的obj對象

3.關於添加addTarget——action方法

爲View對象添加手勢響應以及button添加action時,action(sender){sender爲當前控制器 self} 爲什麼Oc中使用的時候sender爲當前的手勢orbutton對象?
如果Native未實現action方法,那麼會導致獲取方法簽名失敗而導致我們無法拿到正確參數,所以獲得的參數爲當前self.
這裏要記錄強調一下,如添加不存在的action時,要注意action參數不爲當前的事件響應者.

4.JS調用Oc方法,如何支持 多參數多類型 調用

首先,我們要講目標ClassforwardingInvocation:方法替換成我們自己的實現TTPatch_Message_handle
然後通過替換方法的方式,將目標方法的IMP替換爲msg__objc_msgForward,直接開始消息住轉發,這樣直接通過消息轉發最終會運行到我們的TTPatch_Message_handle函數中,在函數中我們可以拿到當前正在執行方法的invocation對象,這也就意味着我們可以拿到當前調用方法的全部信息,並且可以操作以及修改。我們也是通過這個方法來實現,返回值類型轉換。返回值類型轉發這裏涉及到

然後通過替換方法的方式,將目標方法的IMP替換爲msg__objc_msgForward,直接開始消息住轉發,這樣直接通過消息轉發最終會運行到我們的TTPatch_Message_handle函數中,在函數中我們可以拿到當前正在執行方法的invocation對象,這也就意味着我們可以拿到當前調用方法的全部信息,並且可以操作以及修改。我們也是通過這個方法來實現,返回值類型轉換。返回值類型轉發這裏涉及的細節比較多,暫時只說一下最好的一種解決方案。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章