欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

class和object_getClass方法区别

程序员文章站 2022-07-06 11:54:39
一、概述 如上图: 1.内存创建一个instance实例对象(Person *per),同时会创建一个与之对应的类对象(Class perClass)和元类对象(Class perMeta); 注:实例对象通过calloc可创建多个,但类对象和元类对象在内存中只有一份,只创建一次; 2.对象的本质, ......

一、概述

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”

class和object_getClass方法区别

 

//查看类对象自身地址和self.per成员变量isa的地址值

//p/x:以十六进制输出

class和object_getClass方法区别

如上图说明三个问题:

第一,每个实例对象开辟单独的内存;

第二,同一种类对象仅在内存中开辟一次;

第三,此处class方法和object_getclass无任何区别;

 

2)通过类对象获取元类对象

增加代码:

    //元类对象
    class permeta1 = [pergetclass2 class];
    class permeta2 = object_getclass(pergetclass2);

lldb模式:

  报错:引用的成员变量isa不是结构体或共同体的成员;

class和object_getClass方法区别

 

原因:结构体中的isa变量没有暴露出来,从而无法引用; 

class和object_getClass方法区别

 

 解决:自定义相同结构体,并将对象强制转换

//添加代码

struct lyb_objc_class {
    class _nonnull isa;
};

struct lyb_objc_class *pergetclass3 = (__bridge struct lyb_objc_class *)object_getclass(self.per1);

 

//lldb模式:

class和object_getClass方法区别

 

说明:

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模式: 

class和object_getClass方法区别

说明:

1.class返回的依然是元类对象自身,object_getclass返回的是基类的元类对象;

2.基类的元类对象的类名跟类对象的一样,为nsobject;

 

三、结论

当消息对象为实例对象instance时,class与object_getclass返回的对象地址一样;当消息对象为类对象,或元类对象时,class返回的消息对象本身,而object_getclass返回的是下一个对象;

原因:因为class返回的是self,而object_getclass返回的是isa指向的对象;

class和object_getClass方法区别

class和object_getClass方法区别

说明:以上源码查找在github上有演示;

 

github