iOS runtime总结数据结构

runtime 是由c和c++ 汇编实现的一套API,为OC语言加入了面向对象,运行时的功能
运行时(Runtime)是指将数据类型的确定由编译时推迟到了运行时 -
举例子🌰 : extension - category 的区别
平时编写的OC代码,在程序运行过程中,其实最终会转换成Runtime的C语言代 码,RuntimeObject-C 的幕后工作者

runtiem底层的数据结构


8492512-8d419b684704417b.png

首先从objc_class这么一个结构体(数据结构)开始,objc_class继承于objc_object。

objc_object当中有一个成员变量叫isa_t,那么这个isa_t指针就指向一个objc_class类型的类对象(或者说元类对象)。

objc_class主要包含三个成员变量,superClass(指向当前类的父类)、cache_t(用来提供消息传递过程中的缓存方法查找)、class_data_bits_t(类的一些基本信息:类所定义/通过分类所添加 的成员变量,属性,方法列表都在这个数据结构中)

superClass:实际是class类型的,它指向objc_class类型的这样一个指针

cache_t:实际上是装满了bucket_t数据结构的Hash表,维护的也就是这个hash表

class_data_bits_t:实际上是对class_rw_t的数据结构的封装class_rw_t中包含了(class_ro_t类相关的只读信息、protocols类分类中的协议、properties类分类中的属性、methods类分类中的方法)

class_ro_t包含了name类名、methodList类的方法列表--method_t、ivars声明的类的成员变量、类的属性、类的协议。

Runtime基础数据结构如下: objc_object、objc_class、isa指针、method_t

下面讲一下runtime的根元类

objc_object

即id类型(我们平时用的所有对象都是id类型的,在runtime中,id 就是 objc_object结构体)


8492512-a3bc2fb61de10b52.png

objc_object结构体主要包含:

1.isa_t:共用体。

2.关于isa操作相关的一些方法:通过objc_object结构体,来获取isa所指向的类对象,或者通过类对象的isa指针获取它的元类对象一些遍历的放大。

3.弱引用相关:标记一个对象是否曾经有过弱引用指针。

4.关联对象相关方法:我们为对象设置了关联属性,关于关联属性的一些相关方法也体现在objc_object结构体中。

5.内存管理相关的方法实现:MRC下经常用到的runtain,release等方法实现 ,以上均封装在objc_object结构体中

objc_class

OC中的Class,代表一个类,他在runtime中对应objc_class的数据结构(结构体)。

objc_class继承objc_object

所以Class这样一个类也是一个对象,称为类对象,因为它继承自objc_object。

8492512-a3bc2fb61de10b52.png

objc_class包含:

1.objc_class拥有一个superClass指针,指向class类型,(如果说Class是一个类对应的话,superClass指针指向的就是它的父类对象,就是我们平时说的类与父类,实际上是通过objc_class中superClass成员变量来定义的)。

2.cache_t cache成员变量: 方法缓存结构,消息传递时会使用这样的数据结构。

3.class_data_bits_t bits数据结构: 关于类所定义的变量,属性,方法都在bits这样一个成员结构中。

isa指针

它是C++中的共用体,在OC中名称是isa_t

不论是64位架构上(或者32位架构)上面,共用体是64个(或者32个) 0或者1的数字 (按大多数64位分析)

8492512-57c29f350b943c57.png

分两种类型(isa指针是什么含义的时候):

1.指针型isa: 64位的0或者1的整体内容代表所指向的Class的地址,也就是可以通过isa的内容来获得类对象的地址。

2.非指针型isa: isa的值得部分代表Class的地址,之所以这样是因为我们在寻址过程中,只有三四十位数就可以保证我们寻找到所有Class地址了,多出来的位可以用来存储其他相关内容,来达到节省内存的目的。

isa的指向:

8492512-31aaaa8f439a27b2.png

关于对象,它指向类对象

例如我们拥有一个实例,实例就是OC中对应的id类型,在Runtime中就是objc_object,里面有个isa指针,会指向它对应的Class。

关于类对象,指向元类对象

class因为集成objc_object,所以里面也有isa指针,指向其元类对象。

当我们进行方法调用时,调用一个实例的实例方法,实际上是通过isa指针,到它的类对象中,去进行方法查找。

如果我们调用的是类方法,那么是通过类对象的isa指针,到它的元类对象中去查找。

cache_t

是用于快速查找方法执行函数的一个结构(当我们调用一个方法时,如果有缓存,我们就不需要去方法列表中遍历了,可以提高方法调用速度)。

是可增量扩展的哈希表结构(当结构存储量增大的过程中, cache_t会增量扩大它的内存空间来支持更多的缓存,用哈希表实现这个数据结构,是为了提高查找效率)。

cache_t数据结构是计算机局部性原理的最佳应用(计算机局部性原理:在一般调用方法时,有几个方法调用频次较高,把他们放到方法缓存中,下次的命中率就会更高)。

cache_t具体数据结构说明:

8492512-c9c4de5c1b7be234.png

可以理解为是数组来实现的

每个对象都是bucket_t这样的一个结构体, bucket_t有两个主要成员变量,key和IMP。key对应OC中的selector,在调用方法时是个选择器SEL。

IMP理解为无类型的函数指针,可以通过方法选择器的名称key来寻找这个方法的具体实现IMP。

假如现在有个key,可以通过哈希查找算法来定位当前key所对应的bucket_t位于数组当中哪个位置,然后从这个位置中提取出bucket_t中的IMP

class_data_bits_t

这个结构是objc_class中的成员结构

class_data_bits_t主要是对class_rw_t的封装。

class_rw_t代表了类相关的读写信息,例如给类添加的分类的一些方法,属性以及协议等,同时它也对class_ro_t的封装,我们可以随时创建分类,为类增加属性或者方法。rw是readWrite的简写,ro是readOnly的意思,创建类时,添加的成员变量或方法列表在之后就没办法修改了

class_ro_t代表了类相关的只读信息。

8492512-7b6889ab786eccda.png

包含

1.class_ro_t

2.protocols类分类中的协议

3.properties类分类中的属性

4.methods类分类中的方法

这三个数据结构是个二维数组

假如我们三个分类A、B、C,编译顺序A->B->C。这时会逆序遍历并打包成分类数组,分类C中的所有方法都在第一列竖列表中,存在二维数组的第1项。分类B中的所有方法都在第二列竖列表中,存在二维数组的第2项。分类A中的所有方法都在第三列竖列表中,存在二维数组的第3项。

8492512-c8f00fc6a8912b66.jpeg

1.name:类名

2.ivars:声明的类的成员变量

3.类的属性

4.类的协议

5.类的方法列表

除1外都是一维数组

在方法列表当中存储的内容,一般是分类中添加的方法

method_t实际上是对方法的抽象说明

method_t

method_t是对函数四要素(名称、返回值、参数、函数体)的封装

函数四要素决定了函数的唯一性

8492512-2f7d9cc67555e164.jpeg

method_t是个结构体,主要有三个数据类型

1.name函数名称

2.types 函数返回值和参数的集合

3.imp 无类型的函数指针,对应着函数体


8492512-7f5c3789dfa79dd1.jpeg

苹果的Type Encodings技术

types成员属性,实际上表达结构是:

第一个位置永远是函数的返回值类型,后面跟着每个参数的参数类型

参数可以有多个,返回值只有一个

V@:代表types所存储的内容

V对应返回值,@对应参数1,:对应参数2

二、消息的转发机制

https://github.com/LeesimEverglow/LMMessageForwardDemo demo地址

参考资料:https://www.jianshu.com/p/fdd8f5225f0c

消息转发机制共分为3大步骤:

1.Method resolution 方法解析处理阶段处理对象或者类本身是否能响应某方法

2.Fast forwarding 快速转发阶段,某对象的属性中也许该包含了其他类对象,但是这个类对象是否能响应该方法呢,则是快速转发

3.Normal forwarding 常规转发阶段 如果都不能响应,则会创建一个虚基类来看是都能接收,看虚基类能否响应该方法的签名,如果不能则最后抛出异常。

1.消息的转发和替换其实大面积有效的可以使用在混淆上面,让方法名进行混淆,代替执行。比如热更新的混淆

2.可以实现多重代理,让不同对象可以同时代理同个回调,然后在各自负责的区域进行相应的处理,降低了代码的耦合程度。

3.间接实现多继承Objective-C本身不支持多继承,这是因为消息机制名称查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题,但是可以通过消息转发机制在内部创建多个功能的对象,把不能实现的功能给转发到其他对象上去,这样就做出来一种多继承的假象。转发和继承相似,可用于为OC编程添加一些多继承的效果,一个对象把消息转发出去,就好像他把另一个对象中放法接过来或者“继承”一样

三、消息的传递机制 (消息动态绑定机制)

参考:https://juejin.cn/post/6844904014669152270

四、runtime的实际应用

参考:https://www.jianshu.com/p/d761d5938c77

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容