iOS isa指標初始化過程 類結構探索

2021-10-01 15:16:54 字數 3938 閱讀 6886

isa 指標各位域所指代含義

union isa_t 

isa_t(uintptr_t value) : bits(value)

class cls;

uintptr_t bits;

#if defined(isa_bitfield)

struct ;

#endif

};

nonpointer 標記是否是nonpointerisa 如果不是就單純的指向類 如果是就還有下邊的一些資訊 0 是 純的isa。1 是nonpointerisa

has_assoc 是否有關聯物件

has_cxx_dtor 判斷是否有c++或者objc的析構器。如果沒有可以快速釋放

shiftcls 開啟指標優化 儲存類指標

magic 用於除錯判斷當前物件時真的物件還是沒有初始化的空間

weakly_referenced 標記當前物件是否被指向或者曾經指向乙個弱引用物件 如果沒有可以盡快釋放

deallocating 是否正在釋放

has_sidetable_rc 標記當前有沒有sidetable 如果沒有可以更快的釋放

extra_rc 表示當前物件的引用計數 如果小於10 就儲存在這裡 如果大於10 情況變得複雜 要往sidetable中放

isa 指向總結

很經典的那張圖 不再放了 這裡語言總結一下

isa: 類物件的isa指向 類 類的isa指向元類 元類的isa指向跟元類 根源類的isa指向自己

父子關係 子類繼承父類 父類繼承跟類。子元類繼承父元類父元類繼承跟元類 跟元類繼承nsobject

isa 初始化過程

objc_object::initisa(class cls, bool nonpointer, bool hascxxdtor) 

else

}

如果不是nonpointer 就是沒有開啟指標優化 直接指向類。如果開始了指標優化 isa中就儲存了其他資訊。給bits has_cxx_dtor 都賦上初始值

isa 驗證

通過下面獲取isa的源** 一步一步驗證

inline class 

objc_object::isa()

return (class)isa.bits;

#else

return (class)(isa.bits & 0x00007ffffffffff8);

#endif

}

建立乙個繼承子nsobject的類 people類 建立物件p lldb除錯

p/x p.class

(class) $2 = 0x000000010d3085a8 people 類的記憶體位址

x/4gx p

0x6000004cc330: 0x000000010d3085a8 0x0000000000000000

0x6000004cc340: 0x00007f9df0405820 0x0000000000000000

p 0x000000010d3085a8 & 0x00007ffffffffff8

(long) $4 = 4516251048

p/x $4

(long) $4 = 0x000000010d3085a8

通過$2 和$4 可以發現 兩個位址一摸一樣 所以

p物件的isa指向people 也就是他的類

接著列印類的isa

(lldb) x/4gx $2

0x106c28580: 0x0000000106c28558 0x00007fff89cc4580

0x106c28590: 0x00006000036cf7f0 0x0003801800000003

(lldb) p 0x0000000106c28558 & 0x00007ffffffffff8

(long) $3 = 4408378712

(lldb) po $3

people

people 類的isa還是people 其實是指向元類。 這個地方可以通過 objc_getmetaclass(<#const char * _nonnull name#>) 進行驗證

繼續列印元類的isa

x/4gx $3

0x106c28558: 0x00007fff89cc4558 0x00007fff89cc4558

0x106c28568: 0x00006000036cf7a0 0x0003c03100000003

(lldb) p 0x00007fff89cc4558 & 0x00007ffffffffff8

(long) $4 = 140735505253720

(lldb) po $4

nsobject

people類的isa指向 nsobject根元類

繼續探索 我們列印$4 也就是根元類的父類

po 140735505253720 + 8

根元類的父類是nsobject

ios 類探索

objc_class 原始碼

struct objc_class : objc_object 

}

第一步建立people 物件 並且獲取到類

people 類結構

@inte***ce people : nsobject

@property(nonatomic,copy)nsstring *name;

@property(nonatomic,copy)nsstring *location;

@property(nonatomic,assign)int age;

- (void)saygoodby;

+ (void)sayhello;

@end

@implementation people

- (void)saygoodby

+ (void)sayhello

@end

執行一下 命令

people *p = [[people alloc]init];

x/4gx p

0x102e0d730: 0x001d800100002645 0x0000000000000000

0x102e0d740: 0x0000000000000000 0x0000000000000000

(lldb) p 0x001d800100002645 & 0x00007ffffffffff8

(long) $1 = 4294977088

(lldb) po $1

people 此時此刻拿到類 也就是$1

再來看 cache_t

struct cache_t 

};

p $13->basemethodlist

(method_list_t *const) $15 = 0x00000001000020d8 拿到方法列表

就可以通過 p $15.get(index) 獲取方法 這個方法是從 entsize_list_tt 結構題中獲得

這裡掉了乙個坑 開始 saygoodby的例項方法沒實現 所以這個列表中一直沒有

(ivar_t) $41 = 

$40->get(0)

就把我們的成員變數_dohomeword拿到了

總結

經過探索發現 oc的 類本質上是objc_class 的乙個結構體 儲存了 superclass cache bits 方法列表 屬性列表 變數列表 都存在了 class_rw_t 的結構體中,其中類的成員變數在ivars中 屬性在baseproperties 但是在ivars 中也是可以找到帶 _ 的屬性變數 例項方法 在basemethodlist 中找到 類方法 就在元類中。

類初始化過程

class x class y public class z extends x public static void main string args a zyxxb zyxyc yxyzd xyzx解答 靜態變數 靜態 塊 main方法 非靜態變數 塊 構造方法 初始化過程 1.初始化父類中的靜...

類初始化和例項初始化過程

類初始化過程 乙個類要建立例項需要先載入並初始化該類 main方法所在的類需要先載入和初始化 乙個子類要初始化需要先初始化父類 乙個類初始化就是執行 方法 由靜態類變數賦值 和靜態 塊組成 靜態類變數賦值 和靜態 塊從上往下執行 方法只執行一次 例項初始化過程 例項初始化就是執行 方法 方法可能過載...

C 類指標初始化

上面 的 會列印 a c 類指標定義的時候沒有初始化的時候,居然可以安全的呼叫類內部的成員函式而不出錯。在網上查了一下 初始化為null的類指標可以安全的呼叫不涉及類成員變數的類成員函式而不出錯,但是如果類成員函式中呼叫了類成員變數則會出錯,既然賦值為null的情況都可以使用,那麼自然不初始化的類指...