class和object_getClass方法區別
一、概述
如上圖:
1.記憶體建立一個instance例項物件(Person *per),同時會建立一個與之對應的類物件(Class perClass)和元類物件(Class perMeta);
注:例項物件通過calloc可建立多個,但類物件和元類物件在記憶體中只有一份,只建立一次;
2.物件的本質,其實是C語言的結構體struct,各個物件的記憶體結構為:
per:isa指標+僅儲存Person類成員變數的值;
Person:isa指標+superclass指標+儲存成員變數的型別、名稱,協議,物件方法等;
perMeta:isa指標+superclass指標+僅儲存類方法;
3.isa指向:
per:指向類物件Person;
Person:指向元類物件perMeta;
perMeta:指向基類(Root,如:NSObject)的元類物件meta(基類的元類物件的isa指向該元類物件自己);
4.superclass指向:
Person:指向父類>>基類的類物件指向nil;
perMeta:指向父類>>基類的元類物件指向該基類的類物件;
二、程式碼分析
1)通過例項物件per獲取類物件
- (void)viewDidLoad {
[super viewDidLoad];
self.per1 = [[Person alloc] init];
self.per2 = [[Person alloc] init];
//類物件
Class perClass1 = [self.per1 class];
Class perGetClass2 = object_getClass(self.per1);
Class person = [Person class];
//打斷點
NSLog(@"---");
}
進入lldb模式:
//所有的物件(包括類物件和例項物件)所屬類的名字均為“Person”
//檢視類物件自身地址和self.per成員變數isa的地址值
//p/x:以十六進位制輸出
如上圖說明三個問題:
第一,每個例項物件開闢單獨的記憶體;
第二,同一種類物件僅在記憶體中開闢一次;
第三,此處class方法和object_getClass無任何區別;
2)通過類物件獲取元類物件
增加程式碼:
//元類物件 Class perMeta1 = [perGetClass2 class]; Class perMeta2 = object_getClass(perGetClass2);
lldb模式:
報錯:引用的成員變數isa不是結構體或共同體的成員;
原因:結構體中的isa變數沒有暴露出來,從而無法引用;
解決:自定義相同結構體,並將物件強制轉換
//新增程式碼
struct lyb_objc_class { Class _Nonnull isa; }; struct lyb_objc_class *perGetClass3 = (__bridge struct lyb_objc_class *)object_getClass(self.per1);
//lldb模式:
說明:
1.perGetClass2和perGetClass3指的是同一個類物件;
2.perMeta1的地址跟perGetClass2和perGetClass3的地址是相同的,說明此時class並沒有返回元類物件,依然是類物件;
3.perMeta2的地址和perGetClass3->isa指向的地址相同,說明object_getClass返回的是元類物件;
4.元類物件的類名稱和類物件的一樣,依然是Person;
3)通過元類物件獲取基類的元類物件
//新增程式碼
struct lyb_objc_class *perMeta3 = (__bridge struct lyb_objc_class *)object_getClass(perGetClass2);
//還是perMeta2
Class rootMeta1 = [perMeta2 class];
//基類(NSObject)的元類物件
Class rootMeta2 = object_getClass(perMeta2);
//lldb模式:
說明:
1.class返回的依然是元類物件自身,object_getClass返回的是基類的元類物件;
2.基類的元類物件的類名跟類物件的一樣,為NSObject;
三、結論
當訊息物件為例項物件instance時,class與object_getClass返回的物件地址一樣;當訊息物件為類物件,或元類物件時,class返回的訊息物件本身,而object_getClass返回的是下一個物件;
原因:因為class返回的是self,而object_getClass返回的是isa指向的物件;
說明:以上原始碼查詢在GitHub上有演示;