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

class和object_getClass方法区别的更多相关文章
- querySelectorAll 方法相比 getElementsBy 系列方法区别
最近有人问到querySelectorAll 方法相比 getElementsBy 系列方法区别,一时没想起来说些什么,今天查下文档,总结一下它们的区别,以便自己理解. 1. W3C 标准queryS ...
- 浅析对象访问属性的"."和"[]"方法区别
在JavaScript中通常使用”."运算符来存取对象的属性的值.或者使用[]作为一个关联数组来存取对象的属性.但是这两种方式有什么区别了? 例如,读取object中的property属性值 ...
- JAVAAPI学习之Calendar类;Calendar类set()、add()、roll()方法区别
JAVAAPI学习之Calendar类 http://blog.csdn.net/myjlvzlp/article/details/8065775(写的很好,清晰易懂) Calendar类set(). ...
- java中File类中list()和listFiles()方法区别
list()和listFiles()方法区别: 1.返回值类型不同:前者为String数组,后者为File对象数组 2.数组中元素内容不同:前者为string类型的[文件名](包含后缀名),后者为Fi ...
- jQuery方法区别:click() bind() live() delegate()区别
今天看到一篇jquery 事件的文章,自己写了个小例子,虽然2种方式都可以实现,但是不太明白,找了点资料 $("#box1").delegate("p",&qu ...
- JavaScript toString、String和stringify方法区别
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- Java构造器(构造方法)与方法区别
构造器,又称为构造方法.构造器用于构造该类的实例,也就是对象. 格式如下:[修饰符] 类名 (形参列表){//n条语句} 构造方法是一种特殊的方法,与一般的方法区别: 1.构造方法的名字必须与定义 ...
- DevOps - 与敏捷方法区别
章节 DevOps – 为什么 DevOps – 与传统方式区别 DevOps – 优势 DevOps – 不适用 DevOps – 生命周期 DevOps – 与敏捷方法区别 DevOps – 实施 ...
- 从源码看commit和commitAllowingStateLoss方法区别
Fragment介绍 在很久以前,也就是我刚开始写Android时(大约在2012年的冬天--),那时候如果要实现像下面微信一样的Tab切换页面,需要继承TabActivity,然后使用TabHost ...
随机推荐
- 使用 Leaflet 显示 ArcGIS 生成西安80坐标的地图缓存
Leaflet 是一个非常小巧灵活的 Geo js 库,esri 本身也在 Github 上有 leaflet 的相关项目.但是 leaflet 本身支持 Web Mercator Auxiliary ...
- c# 异步和同步问题(转载)
[C#] 谈谈异步编程async await 为什么需要异步,异步对可能起阻止作用的活动(例如,应用程序访问 Web 时)至关重要. 对 Web 资源的访问有时很慢或会延迟. 如果此类活动在同步过 ...
- 润乾在东方通tongweb5.0上部署手册
作为国内领先的中间件开发商,东方通是国内最早研究J2EE技术和开发应用服务器产品的厂商.应用服务器TongWeb的开发目标,是利用公司在中间件 领域的技术优势,实现符合J2EE规范的企业应用支撑 ...
- linux 光盘yum源搭建
1.挂载光盘 2.进入 /etc/yum.repos.d 目录,修改其它配置文件后缀名 mv CentOS-Base.repo CentOS-Base.repo.bakmv CentOS-CR.rep ...
- 异度之刃 Xenoblade 后感
WII版重置的N3DS劣化版异度之刃终于通关了.在出色的自制系统的快乐NTR的帮助下,充分体验到了神作的剧情史诗感. 关于游戏的玩法系统,从现在来看8年前的游戏,缺点显而易见,特别是跑地图这回事,地图 ...
- 使用cancelBubble竟然可以阻止所有浏览器的冒泡?
以前一直以为cancelBubble是IE8及以下的专属,今天做一个测试的时候意外发现了所有浏览器都支持,便提出来希望有哪位解释下. 1.使用原生js在FF下和chrome下两种方法都可以阻止冒泡 d ...
- HBase Region分裂实现
分裂策略 不同的分裂策略的实现需要继承RegionSplitPolicy,主要实现两个方法: shouldSplit()表示是否需要分裂 getSplitPoint()得到分裂点rowkey 从 HB ...
- ssh终端常用快捷键
ssh终端常用快捷键 快捷键 描述 Ctrl+a 光标移动到行首 Ctrl+e 光标移动到行尾 Ctrl+c 终止当前程序 Ctrl+d 删除光标前的字符,或者推出当前中断 Ctrl+l 清屏 Ctr ...
- UIWebView如何加载本地图片
UIWebView如何加载本地图片 UIWebView加载本地图片是有实用价值的.比方说,有时候我们需要本地加载静态页来显示相关帮助信息,而这些帮助信息当中含有很多很多的富文本,用代码实现难度较大,这 ...
- Beautifulsoup模块安装之pip命令
1.在python引用 BeautifulSoup >>>from bs4 import BeautifulSoup 发现没有该模块 2.Linux输入 # pip install ...