1. 程式人生 > 實用技巧 >class和object_getClass方法區別

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上有演示;

補充:class <=> objc_getClass

//程式碼

//clang

GitHub