class和object_getClass方法区别

By | 2019年8月26日

一、概述

 

如上图:

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

 

发表评论