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上有演示;
上一篇: 羊栖菜是什么,该怎么吃
下一篇: 红毛丹什么季节成熟、有什么样的价值
推荐阅读
-
浅析C#中静态方法和非静态方法的区别
-
浅析ThinkPHP中execute和query方法的区别
-
锚文本和超链接的区别,五分钟让你搞懂这两者的使用方法
-
浅谈Java异常的Exception e中的egetMessage()和toString()方法的区别
-
锚文本和超链接的区别,五分钟让你搞懂这两者的使用方法
-
方法重载和方法重写的区别
-
java中timer的schedule和scheduleAtFixedRate方法区别详解
-
SQLSERVER全文目录全文索引的使用方法和区别讲解
-
Vue的watch和computed方法的使用及区别介绍
-
详解Node.js中path模块的resolve()和join()方法的区别