【OC底层】OC对象本质,如 isa, super-class
Objective-C的本质

2、在OC中的所有面向对象的实现,都是基于C/C++的数据结构实现的
3、将Objective-C代码转换为C\C++代码
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件
注:如果需要链接其他框架,使用-framework参数。比如-framework UIKit
一个OC对象在内存中是如何布局的?
NSObject基类的实现:

子类的实现:

子类的拆解:

1、在OC中的对象,就是 C++中的 struct来实现的
2、每个OC对象中都会有一个 isa 的指针,isa指向的是 objc_class 结构体,如下(旧版OC原码):

通过代码可以看得出在OC2 中已经不能通过 objc_method_list 之类的方式获取方法名、实例、协议之类的了,需要使用新的方法获取
思路:自定义一个和oc源码中 objc_class 结构一样的结构体,然后将对象的isa 强转成我们自定义的那个,再去调用
如下是OC中objc_class的源码(新版OC原码):

新的OC版本中方法、属性、协议相关数据都存在了 bits
通过 bits.data() 返回 class_rw_t 结构,如下:

bits.data() 的实现:


其中需要 通过 & FAST_DATA_MASK 才能获取到真实的地址
整体数据结构图:

OC对象的分类
Objective-C对象主要分为以下3类:
1> instance对象(实例对象)
2> class对象(类对象)存储实例方法列表等信息
3> meta-class对象(元类对象)存储类方法列表等信息
注:一个类只会有一个类对象,一个元类对象,可以有多个实例对象
通过下面的代码可以分别获取3种对象:
NSObject* obj = [[NSObject alloc]init];
const char* className = [@"NSObject" cStringUsingEncoding:NSUTF8StringEncoding]; // 实例对象
NSLog(@"instance: %p",obj); // 类对象
NSLog(@"NSObject class: %p", [NSObject class]);
// 同上
NSLog(@"obj class: %p", [obj class]);
// 如果传实例对象,获取到的还是类对象
NSLog(@"get class: %p", object_getClass(obj));
// 通过类名获取类对象
NSLog(@"objcClass: %p", objc_getClass(className)); // 元类对象
// 必需要传入类对象才能获取元类对象
NSLog(@"meta-class: %p", object_getClass([obj class]));
// 通过类名获取元类对象
NSLog(@"objcMetaClass: %p", objc_getMetaClass(className)); // 判断是否是metaClass
NSLog(@"isMetaClass1:%i",class_isMetaClass([NSObject class])); // 0
NSLog(@"isMetaClass2:%i",class_isMetaClass([[NSObject class] class])); // 0
NSLog(@"isMetaClass3:%i",class_isMetaClass(object_getClass([NSObject class]))); // 1
输出:
-- ::37.363 OC_isa_supclass[:] instance: 0x100202b50
-- ::37.364 OC_isa_supclass[:] NSObject class: 0x7fff760140f0
-- ::37.364 OC_isa_supclass[:] obj class: 0x7fff760140f0
-- ::37.364 OC_isa_supclass[:] get class: 0x7fff760140f0
-- ::37.365 OC_isa_supclass[:] objcClass: 0x7fff760140f0
-- ::37.365 OC_isa_supclass[:] meta-class: 0x7fff76014118
-- ::37.365 OC_isa_supclass[:] objcMetaClass: 0x7fff76014118
2018-09-27 14:49:27.746 OC_isa_supclass[1360:106109] isMetaClass1:0
2018-09-27 14:49:27.746 OC_isa_supclass[1360:106109] isMetaClass2:0
2018-09-27 14:49:27.746 OC_isa_supclass[1360:106109] isMetaClass3:1
1> 需要注意的是 object_getClass 方法,当传入的是实例对象,就会返回类对象,如果传入的是类对象就会返回元类对象
2> 还有一点就是 [[NSObject class] class] 这样是获取不到元类对象的,这样获取到的还是类对象
3> 另外里面还有两个 objc_ 开头的方法,分别是获取类对象和元类对象,但它是传入类名字符串就可以了,需要转换成 C语言的char
1、instance对象

它们是不同的两个对象,分别占据着两块不同的内存


instance对象在内存中保存的信息包括:
1> isa指针
2> 其它成员变量
2、class对象

NSObject类对象只有一个,所有实例对象的class属性获取到的都是同一个类对象
class对象在内存中存储的信息主要包括:
1> isa指针
2> superclass指针
3> 类的属性信息(@property)、类的对象方法信息(instance method)
4> 类的协议信息(protocol)、类的成员变量信息(ivar)
....
3、meta-class对象

每个类在内存中有且只有一个meta-class对象
meta-class对象在内存中存储的信息主要包括:
1> isa指针
2> superclass指针
3> 类的类方法信息(class method)
...
注:class 对象和 meta-class 对象都是 Class 类型的,它们其实结构都是一样的,class对象中一样会包含 类方法,只不过那个类方法是 空的而已。
同样,meta-class对象中也有 类的属性、对象方法、协议、成员变量,不过那些对应的值也都是空
isa指针
上面我们通过源码可以看到每个对象都有一个 isa 指针,isa指针作用是干嘛的呢?

通过上图可以看出:
1> instance的isa指向class
当调用对象方法时,通过instance的isa找到class,最后找到对象方法的实现进行调用
2> class的isa指向meta-class
当调用类方法时,通过class的isa找到meta-class,最后找到类方法的实现进行调用
class对象的superclass指针
superclass是用于找父类的,比如子类调用某个方法,如果子类中没有,就会去父类找,底层就是通过superclass找到父类的,如下图:

当Student的instance对象要调用Person的对象方法时,会先通过isa找到Student的class,然后通过superclass找到Person的class,最后找到对象方法的实现进行调用
meta-class对象的superclass指针
meta-class中的superclass基本和 class对象中的一样,不过有一点点区别,如图:

当Student的class要调用Person的类方法时,会先通过isa找到Student的meta-class,然后通过superclass找到Person的meta-class,最后找到类方法的实现进行调用
有什么区别呢?从这图可能看不出来,区别就是如果基类的meta-class中都找不到类方法,那么它就会去从基类对象里面去找对象方法,OC的底层其实是不区分 对象方法与类方法的。
isa、superclass总结

这张图能够清楚的描述 isa和superclass的作用和关系,下面是备注了一下,看得更加懂点。

- instance的isa指向的是class对象
- class的isa指向的是meta-class对象
- 所有的meta-class的isa指向的都是基类的meta-class对象(重点)
- class的superclass指向的是父类的class对象,如果没有父类,superclass指针为nil
- meta-class的superclass指向的是父类的meta-class对象
- 基类的meta-class的superclass指向的是基类的class对象(重点)
instance调用对象方法的轨迹:
实例对象会先通过isa找到class对象,判断里面有没有要调用的方法,如果有就直接调用,没有就会通过class对象中的superclass找到父类,然后在父类中判断是否有该方法,如果还没有就接着往上找。
class调用类方法的轨迹:
isa找meta-class,方法不存在,就通过superclass找父类,最后基类mate-class也没有的话还会去基类对象找,这样就会导致调用类方法可能会去调用实例对象的方法
isa指针的一些问题
上面已经说到了instance对象的isa指针指向的是class对象,那就是说instance对象的isa指针内存地址是不是就是class对象的内存地址呢?
如果在以前的32位系统中确实如此,在64位系统中不是的,里面有一个点操作, ISA_MASK

其中arm64和x86架构的这个 ISA_MASK的偏移地址是不一样的,如下图:

class、meta-class对象的本质结构都是struct objc_class,如下图:
-----------------------------
本文参考借鉴MJ的教程视频,非常感谢.
【OC底层】OC对象本质,如 isa, super-class的更多相关文章
- OC基础--类的本质
类的本质: 类的本质其实也是一个对象(类对象),只要有了类对象, 将来就可以通过类对象来创建实例对象 程序中第一次使用该类的时候被创建,在整个程序中只有一份.此后每次使用都是这个类对象,它在程序运行时 ...
- OC基础--OC中的类方法和对象方法
PS:个人感觉跟C#的静态方法和非静态方法有点类似,仅仅是有点类似.明杰老师说过不要总跟之前学过的语言做比较,但是个人觉得,比较一下可以加深印象吧.重点是自己真的能够区分开! 一.OC中的对象方法 1 ...
- oc总结 --oc基础语法相关知识
m是OC源文件扩展名,入口点也是main函数,第一个OC程序: #import <Foundation/Foundation.h> int main(int argc, const cha ...
- 【OC底层】一个OC对象占用多少内存?
查看一个NSObject对象占用多少内存 1.引入头文件: #import <objc/runtime.h> #import <malloc/malloc.h> 2.代码如下: ...
- OC对象本质
@interface person:NSObject{ @public int _age; } @end @implementation person @end @interface student: ...
- 【OC底层】AssociatedObject 关联对象
如何实现给分类“添加成员变量”? 默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中.但可以通过关联对象来间接实现 关联对象提供了以下API 1> 添加关联对象 void objc_s ...
- iOS开发——底层OC篇&运行时常用
运行时常用 什么是Runtime(前面的文章已经说的很清楚了,这里就简单的介绍一下) 我们写的代码在程序运行过程中都会被转化成runtime的C代码执行,例如[target doSomething]; ...
- oc学习之对象在内存的位置
对象在内存中的存储 1. 内存中的五大区域. 栈: 存储局部变量. 堆: 允许程序员手动在堆区申请指定的连续的字节数的空间来使用. BSS段: 存储未初始化的全局变量.静态变量. 数据段(常量区): ...
- OC语言类的本质和分类
OC语言类的深入和分类 一.分类 (一)分类的基本知识 概念:Category 分类是OC特有的语言,依赖于类. 分类的作用:在不改变原来的类内容的基础上,为类增加一些方法. 添加一个分类: 文件 ...
随机推荐
- JavaScript-原型&原型链&原型继承&组合函数
小小的芝麻之旅: 今天学习了js的原型,要说原型,我们先简单说一下函数创建过程. 原型 每个函数在创建的时候js都自动添加了prototype属性,这就是函数的原型,原型就是函数的一个属性,类似一个指 ...
- css中小知识点总结
rgba:即rgb+a, a为图片透明度,a范围是0~1,越小就表示越透明 :hover 即鼠标悬停时改变样式,不仅仅能用在a元素上. <form>标签表示向浏览器提交表单,一般会包裹着输 ...
- C++学习笔记(2)----类模板和友元
当一个类包含一个友元声明时,类与友元各自是否是模板是相互无关的.如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例.如果友元自身是模板,类可以授权给所有友元模板实例,也可以只授权给特定 ...
- OFDM正交频分复用---基础入门图示
@(162 - 信号处理) 整理转载自:给小白图示讲解OFDM 下面以图示为主讲解OFDM,以"易懂"为第一要义. 注:下面的讨论如果不做说明,均假设为理想信道. *** 一张原理 ...
- [转]乔布斯的薄伽梵歌 Steve’s Bhagavat Gita
SRC: http://www.brucejia.net/ 2014年4月4日未分类apple.ios.steve jobs 编辑 Your time is limited, so don't was ...
- XSS防范之Encode(转)
防范XSS有三道防火墙:数据的输入校验,数据输出Encode,浏览器安全(主要就是CSP),这里主要介绍Encode. #用于XSS防范的Encode 用户防范XSS的Encode主要有三种:Html ...
- Gartner发布最新魔力象限报告,微软领跑数据库市场(编译自TechRepublic)
知名调研机构Gartner发布了最新的<2015年数据库管理系统魔力象限调研报告>.报告显示,微软.甲骨文和AWS是数据库市场的三大领导厂商. 此份报告对知名的商用以及开源数据库厂商进行了 ...
- 前端静态资源版本更新与缓存之——通过gulp 在原html文件上自动化添加js、css版本号
原理 修改js和css文件 通过对js,css文件内容进行hash运算,生成一个文件的唯一hash字符串(如果文件修改则hash号会发生变化) 替换html中的js,css文件名,生成一个带版本号的文 ...
- MySQL -Naivacat工具与pymysql模块
Navicat 在生产环境中操作MySQL数据库还是推荐使用命令行工具mysql,但在我们自己开发测试时,可以使用可视化工具Navicat,以图形界面的形式操作MySQL数据库. 官网下载:https ...
- Asp.Net MVC源码调试
首先下载MVC源代码,下载地址为:https://aspnetwebstack.codeplex.com/ 打开项目,卸载test文件夹下的所有项目和System.Web.WebPages.Admin ...