runtime 是ios的執行時,用於實現ios載入和呼叫屬性和方法。
函式中load方法沒有使用runtime機制,是底層直接呼叫的函式。load執行順序是由編譯時的檔案順序相同,先編譯的先執行load,類優先於分類的順序呼叫+load
方法。
initialize
+initialize
方法是在類或類的子類收到第一條訊息之前被呼叫的,這裡所指的訊息包括例項方法和類方法的呼叫。
也就是說+initialize
方法是以懶載入的方式被呼叫的,如果一直沒有給乙個類或他的子類傳送訊息,那麼這個類的+initialize
方法是永遠不會呼叫的。
當我們向某個類傳送訊息時,runtime
會呼叫imp lookupimporforward(...)
這個函式在類中查詢相應方法的實現或進行訊息**,開啟objc-runtime-new.h
找到這個函式:
imp lookupimporforward
(class cls, sel sel, id inst,
bool initialize, bool cache, bool resolver)..
.}
從中可以看到當類沒有初始化時,會呼叫_class_initialize(class cls)
對類進行初始化:
void
_class_initialize
(class cls)..
....
if(reallyinitialize)
// 傳送呼叫類方法initialize的訊息((
void(*
)(class, sel)
)objc_msgsend)
(cls, sel_initialize);.
....
.}
在這裡,先是對入參的父類進行遞迴呼叫,以確保父類優先於子類初始化。
+initialize
方法在runtime
中是以傳送訊息的方式呼叫的,所以子類會覆蓋父類的實現,分類會覆蓋類的實現,多個分類只會呼叫乙個分類的+initialize
方法。
分類通過runtime動態將分類的屬性和方法合併到類物件,元類物件中。
#import "classname + categoryname.h"
#import static void *strkey = &strkey;
@implementation classname (categoryname)
-(void)setstr:(nsstring *)str
-(nsstring *)str
method swizzling
每個類都維護乙個方法(method)列表,method則包含sel和其對應imp的資訊,方法交換做的事情就是把sel和imp的對應關係斷開,並和新的imp生成對應關係。
交換前:asel->aimp bsel->bimp
交換後:asel->bimp bsel->aimp
方法交換之後,「方法的實現」 變成了 「你的處理**」 + 「方法的實現」
+ (void)swizzlemethods:(class)class originalselector:(sel)origsel swizzledselector:(sel)swizsel else
}
呼叫過程,涉及到了isa指標
isa
ps:mask 掩碼,一般用來進行按位(與&)運算。
iOS 類的底層原理
首先我們探索來例項物件 類物件 元類之間的關係,執行下面 可以看到class1 class2 class3列印結果一樣,我們是不是可以認為類物件只有乙個,元類是乙個虛擬的類由系統幫我們建立,是類物件所屬的類,而元類歸屬是根元類,根元類的歸屬是自身。例項物件 person p person alloc...
iOS 底層原理之 Block
block 本質上也是乙個 oc 物件,它內部也有個 isa 指標 block 是封裝了函式呼叫以及函式呼叫環境的 oc 物件 block 的底層結構如下圖所示 原始碼解析 struct gsblock load block impl 0 block impl struct block impl g...
iOS底層原理總結 OC方法的本質
int main int argc,const char argv return 0 可以看出在我們進行lgperson初始化的時候,我們都知道會呼叫alloc,init.我這裡為了簡單只呼叫 new 但是底層不是像我們利用呼叫的,而是呼叫了乙個函式objc msgsend這就是我們訊息傳送的方法,...