小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
什么是runtime?
runtime 一套C、C++、汇编编写的API,为OC提供运行时功能。能够将数据类型的确定由编译期推迟到运行时。 问题?方法的本质?或runtime的消息机制? 方法的本质就是消息发送 发送消息的主要流程:
- 1.快速查找:
objc_msgSend
查找cache_t
缓存消息 - 2.慢速查找:递归自己和父类查找方法
lookUpImpOrForworw
- 3.查找不到消息,进行动态方法解析:
resolveInstanceMethod
- 4.消息快速转发:
forwardingTargetForSelector
- 5.消息慢速转发:消息签名
methodSignatureForSelector
和分发forwardinvocation
- 6.最终仍未找到消息:程序crash,报经典错误
unrecognized selector sent to instance XXX
SEL是什么?IMP是什么?两者有什么联系? - SEL是方法编号,即方法名称,在
dyld
加载镜像时,通过read_image
方法加载到内存的表中了。 - IMP时函数实现指针,找IMP就是找函数的过程
- 两者的关系:sel相当于书本的目录标题,imp就是书本的页码。查找具体的函数就是想看这本书里面具体篇章的内容:
- 1.我们首先知道想看什么,也就是title -sel
- 2.然后根据目录对应的页码 -imp
- 3.打开具体的内容 -方法的具体实现
runtime应用
-
- 方法的交换:具体应用拦截系统自带的方法调用(
Method Swizzling
黑魔法)
- 方法的交换:具体应用拦截系统自带的方法调用(
- 2.实现给分类增加属性
- 3.实现字典的模型和自动转换
- 4.
JSPatch
替换已有的OC方法实现等 - 5.
aspect
切面编程 能否向编译得到的泪中增加实例变量?能否向运行时创建的类中添加实例变量?为什么? - 1.不能向编译后得到的类中增加实例变量。
- 2.可以向运行时创建的类中添加实例变量。
- 3.因为编译后的类已经注册在
runtime
中,类结构体中的objc_ivar_list
实例变量的链表和instance_size
实例变量的内存大小已经确定,同时runtime
会调用class_setIvarLayout
或class_setWeakIvarLayout
来处理strong
、weak
引用,所以不能向存在的类中添加实例变量。运行时创建的类是可以添加实例变量,调用class_addIvar
函数。但是得在调用objc_allocateClassPair
之后,objc_registerClassPair
之前,原因同上。 Category中添加属性和成员变量的区别 - 1.
Category
它的主要作用是在不改变原有类的前提下,动态的给这个类添加一些方法。 - 2.分类的结构体指针中,没有属性列表,只有方法列表。原则上它只能添加方法,不能添加属性(成员变量),但是可以借助运行时关联对象
objc_setAssociatedObject(self,@selector(name),name,OBJC_ASSOCIATION_COPY_NONATOMIC);
、objc_getAssociatedObject(self,@selector(name));
. - 3.分类中可以写
@property
,但不会生成setter/getter
方法声明和实现,也不会生成私有的成员变量,会编译通过,但是引用变量会报错。 - 4.如果分类中有和原有类同名的方法,会优先调用分类中的方法,就是说会忽略原有类的方法,同名方法调用的优先级为 分类 本类 父类,因为方法是放在方法栈中,遵循先进后出原则。