您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關使用objc runtime實現iOS怎么閉環的懶加載功能,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
懶加載形式如下
- (id)lazyloadProperty{ if(_lazyloadProperty == nil){ _lazyloadProperty = [XClass ...]; } return _lazyloadProperty; }
一般使用宏定義可以輕松完成。但是沒有一致性,移植差。
利用objc runtime的動態性實現懶加載可以實現即可增加又可刪除功能,也可以避免污染類型。該三方彌補了目前沒有閉環實現懶加載三方的空缺。
主要流程:
實例或者類的懶加載
如果是實例對象則鉤住并修改類型將其子類化
對該類型進行method swizzling
如果現在進行解綁,則判斷是否是自己實現的方法.如果是自己實現的方法->5,否則->6
調用method swizzling還原
刪除這個類型的這個方法
難點:
自己實現method swizzling
重新實現objc1時代的方法class_removeMethods
鉤住運行時中的runtimelock,實現修改類型數據時的安全性
我們再實現method swizzling時的兩個API
OBJC_EXPORT IMP _Nullable class_replaceMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0); OBJC_EXPORT void method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
不管使用哪種,如果這個類型沒有實現該方法而是父類實現的話,就需要動態增加一個方法。動態增加的方法在Objc1時代,是可以通過下列方法刪除的:
OBJC_EXPORT void class_removeMethods(Class _Nullable, struct objc_method_list * _Nonnull) OBJC2_UNAVAILABLE;
Objc2時代之后runtime被重寫后沒有該方法了,并且新的runtime的類結構看起來就沒打算讓開發者刪除方法,所以這里將過程記下。
首先看類讀寫器的結構class_rw_t
struct class_rw_t { // Be warned that Symbolication knows the layout of this structure. uint32_t flags; uint32_t version; const class_ro_t *ro; method_array_t methods;//刪除這里的一個方法 property_array_t properties; protocol_array_t protocols; Class firstSubclass; Class nextSiblingClass; char *demangledName; #if SUPPORT_INDEXED_ISA uint32_t index; #endif };
method_array_t繼承于list_array_tt<method_t, method_list_t>
,它是數組結構。存儲的內容是method_list_t.
method_list_t又繼承于entsize_list_tt<method_t, method_list_t, 0x3>
,他也是數組結構。
整個method_array_t結構是二維數組。每次刪掉一個method_t需要用新method_list_t替換原對象。
然后是線程安全的問題,需要獲取到蘋果在操作類型的時候使用的讀寫鎖(pthread_rw_lock_t runtimelock)。沒有這把鎖任何對runtime的修改都是不可靠的。
最終采取的方式是:劫持暴露了符號的系統函數然后阻塞線程
劫持系統C函數使用的是臉書的魚鉤,這個鉤子在macOS其實也是可以正常工作的。
剩下的就是尋找合適的函數了,這函數要滿足兩個條件:
該函數在符號表中存在
函數內部在lock runtimelock之后存在滿足條件1的第二個函數
找了半天發現最合適的只有objc_allocateProtocol()了,objc_allocateProtocol內部會調用calloc(),所以第二個被劫持函數就是calloc。為了減小calloc的開銷,需要稍微做一些工作。
對每次調用進行比較線程ID的操作顯然比暴力阻塞線程好。
減小劫持后的calloc的調用棧。
看完上述內容,你們對使用objc runtime實現iOS怎么閉環的懶加載功能有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。