谈到runtime我们不免想到isa指针。那什么是isa指针呢?OC语言里面每个对象都会有一个隐藏的数据结构,这个数据结构同时是OC对象的第一个成员变量。其实这个数据结构就是我们的isa指针。
那么isa指针有什么作用呢?那我们接下来看一下isa的指针的作用。
isa指针通常用来指向对象所属的类,从而通过调用方法时通过isa指针找到相应的方法和属性。(元类的isa指针指向的就是元类)。
接下来我们看一下isa历史优化。
在arm64架构之前,isa就是一个普通的指针,储存着Class,Meta-Class对象的内存地址。
从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来储存更多的信息。
接下来我们谈谈位域位域储存了哪些信息?
首先我们看一下 nonpointer 这个里面存在0种情况 如果是0,就是说明是arm64架构之前。1代表已经优化过了,也就是arm64架构之后的。
接下来我们看一下has_assoc 这个作用是否有设置过关联对象,如果没有释放时会更快。
接下来我们看一下has_cxx_dtor 这个作用是否有C++析构函数,如果没有释放会更快。
接下来我们看一下shiftcls 这个里面储存着Class,Meta-Class对象的内存地址。
接下来我们看一下 magic 这个用于在调试时分辨对象是否完成初始化。
接下来再看一下 weakly_referenced 这个是判断是否被弱引用指向过,如果没有,释放时会更快。
接下来再看一下 deallocating 这个主要判断对象是否正在释放。
接下来再看一下 extra_rc 里面储存的值是引用计数减1
接下来再看一 has_sidetable_rc 判断引用计数器是否过大无法储存在isa中,如果为1那么引用计数会储存在一个叫SideTable的类的属性中。
然后我们看一下Class结构
接下来我们分析一下 class_rw_t。这个里面的方法,属性,协议是二维数组,可读可写,包含了类的初始化内容,分类的内容。
接下来我们分析一下 class_ro_t。 这个里面基类方法,基类协议,基类属性,成员变量,是只读的,包含了类的初始化内容。
接下来我们分析一下method_t。 这个是对方发/函数的封装。接下来我们看一下method_t的样子
SEL代表方法/函数名,一般叫做选择器。
可以通过@selector()和sel_registerName()获得。
可以通过sel_getName()和NSStringFromSelector()转成字符串。
不同类中的相同名字的方法,所对应的方法选择器是一样的。 我们看一下 typedef struct objc_selector * SEL 。
types包含了函数的返回值,参数编码的字符串。
接下来我们谈一下方法缓存 也就是cache_t 接下来我们看一下它的样子
其内部是用散列表(哈希表) 来缓存曾经调用的方法,从而提高方法的速度。
isa我们暂时介绍这么多。接下来重头戏来了,也就是我们的消息转发机制。哦,不对还没有谈runtime? 什么是runtime?
OC是一门动态性比较轻的编程语言,允许很多操作推迟到程序运行时再近些,OC的动态性就是由runtime来支撑和实现的,runTime是一套C语言的API,封装了很多动态性相关的函数,平时编写的OC代码,底层都是转换成了Runtime API进行调用。
runtime的具体应用
利用关联对象(AssociatedObject) 给分类添加属性
遍历类的所有成员变量 (修改textfield的占位文字的颜色,字典转模型,自动归档解档)
交换方法实现(交换系统的方法)
利用消息转发机制解决方法找不到的异常问题
OC中的方法调用,其实都是转换为objc_msgSend函数的调用。
其流程大致分为,消息发送(当前类,父类中查找),动态方法解析,消息转发三大阶段。
OC中的方法调用其实都是转成了objc_msgSend函数的调用,receiver(方法调用者)发送了一条消息(selector方法名)
我们先看第二个流程---------消息发送(当前类,父类中查找)
我们首先判断当前方法的调用者是否为存在,如果不存在我们则去看方法调用者的父类是否存在。
如果当前类存在-》我们就去方法的缓存中找-》方法里面去找
// 下面这条链找到了方法就会缓存到缓存方法里面
-》父类缓存方法中找 -》父类方法中找
// 已经排序的,二分查找法 没有排序的,遍历查找
// 调用者通过isa指针找到调用者的类
// 调用者通过父类指针找到父类
我们接下来看第一个流程 动态方法解析
如果调用了对象方法首先会进行+(BOOL)resolveInstanceMethod:(SEL)sel判断
如果调用了类方法 首先会进行 +(BOOL)resolveClassMethod:(SEL)sel判断
同时上面2个方法来动态添加方法实现
动态解析后,会重新走"消息发送"的流程
从当前类的缓存方法中查找方法开始
最后我们来看消息转发的第三个流程 消息转发
// 快速转发 返回值===nil 则往下走
-(id)forwardingTargetForSelector:(SEL)aSelector{}
// 常规转发
-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector
网友评论