1.方法交换的原理及应用场景
在OC语言的runtime特性中,调用一个对象的方法就是给这个对象发送消息。是通过查找接收消息对象的方法列表,从方法列表中查找对应的SEL,这个SEL对应着一个IMP(一个IMP可以对应多个SEL),通过这个IMP找到对应的方法调用。
在每个类中都有一个Dispatch Table,这个Dispatch Table本质是将类中的SEL和IMP(可以理解为函数指针)进行对应。而我们的Method Swizzling就是对这个table进行了操作,让SEL对应另一个IMP。
需要把所有的UILabel的字体放大2号
需要给所有ViewController添加友盟统计
防奔溃处理:数组越界问题
统计VC加载次数并打印
2.消息转发的过程
https://www.jianshu.com/p/9263720cbd91
第一步:Method resolution 方法解析处理阶段
对象在收到无法解读的消息后,首先会调用+(BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:(SEL)sel, 询问是否有动态添加方法来进行处理;如果YES则能接受消息, NO不能接受消息 进入第二步;
第二步:Fast forwarding 快速转发阶段 (后面阶段都针对对象来处理,不考虑类方法)
既然第一步已经问过了,没有新增方法,那就问问有没有别人能够帮忙处理一下啊,调用的是- (id)forwardingTargetForSelector:(SEL)aSelector这个方法。
第三步:Normal forwarding 常规转发阶段
如果第二步返回self或者nil,则说明没有可以响应的目标 则进入第三步。
第三步的消息转发机制本质上跟第二步是一样的都是切换接受消息的对象,但是第三步切换响应目标更复杂一些,第二步里面只需返回一个可以响应的对象就可以了,第三步还需要手动将响应方法切换给备用响应对象。
3.分类加载的原理及顺序?
https://www.jianshu.com/p/fa66c8be42a2
分类的实现原理是将category中的方法,属性,协议数据放在category_t结构体中,然后将结构体内的方法列表拷贝到类对象的方法列表中。
后编译的分类先调用,因为每次编译的分类都会放到数组的前面去,本类的在最后
4.KVO原理
https://www.jianshu.com/p/5477cf91bb32
当一个对象使用了KVO监听,iOS系统会修改这个对象的isa指针,改为指向一个全新的通过Runtime动态创建的子类,子类拥有自己的set方法实现,set方法实现内部会顺序调用willChangeValueForKey方法、原来的setter方法实现、didChangeValueForKey方法,而didChangeValueForKey方法内部又会调用监听器的observeValueForKeyPath:ofObject:change:context:监听方法。
5.weak指针自动置nil的原理
1 初始化步骤 runtime 会调用objc_initWeak,初始化一个新的weak指针指向对象的地址。
2 添加引用的步骤 objc_initWeak 函数会调用 objc_storeWeak 函数,这个函数的作用是更新指针指向,创建对应的弱引用表
3 释放的时候 最后一步是触发调用arr_clear_deallocating 函数 ,根据对象的地址将所有weak指针地址的数组,遍历数组把其中的数据置为nil。
6.runtime如何实现weak属性?
https://blog.csdn.net/xiaohuoziooo/article/details/88029300
Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个哈希表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。
当weak引用指向的对象被释放时,如何去处理weak指针?
a. 从weak表中获取被释放对象的地址为键值的记录
b. 将包含在记录中的所有附有 weak修饰符变量的地址,赋值为 nil
c. 将weak表中该记录删除
d. 从引用计数表中删除废弃对象的地址为键值的记录
7.runtime如何通过selector找到对应的IMP地址?
https://www.jianshu.com/p/8b6a723e22e5
对象中有类方法和实例方法的列表,列表中记录着方法的名词、参数和实现,而selector本质就是方法名称,runtime通过这个方法名称就可以在列表中找到该方法对应的实现。
IMP class_getMethodImplementation(Class cls, SEL name);
IMP method_getImplementation(Method m)
8.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
https://www.jianshu.com/p/4341611499f9
不能向编译后得到的类中增加实例变量。
能向运行时创建的类中添加实例变量。
解释下:
因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表和 instance_size 实例变量的内存大小已经确定,同时 runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量。
运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前,原因同上。
9.有没有用过运行时,用它都能做什么?(交换方法,创建类,给新创建的类增加方法,改变isa指针)
网友评论