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

 

GitHub