一、Runtime Asssociate方法关联的对象,需要我们手动释放吗?
当我们对象释放时,会调用dealloc
1、C++函数释放 :objc_cxxDestruct
2、移除关联属性:_object_remove_assocations
3、将弱引用自动设置nil:weak_clear_no_lock(&table.weak_table, (id)this);
4、引用计数处理:table.refcnts.erase(this)
5、销毁对象:free(obj)
所以,关联对象不需要我们手动移除,会在对象析构即dealloc时释放.
二、方法的调用顺序
类的方法 和 分类方法 重名,如和调用,是什么情况?
如果同名方法是普通方法,包括initialize--先调用分类方法
因为分类的方法是在类realize实现之后再attach进去的,插在类的方法的前面,所以优先调用分类的方法(注意:不是分类覆盖主类!!)
initialize方法什么时候调用?initialize方法也是主动调用,即第一次消息发送时调用,为了不影响整个load,可以将需要提前加载的数据写到initialize中
如果同名方法是load方法-- 先主类load,后分类load(分类之间,看编译的顺序)可以参考iOS之武功秘籍⑧: 类和分类加载过程文章中的load_images原理分析
三、Runtime是什么?
runtime是由C和C++汇编实现的一套API,为OC语言加入了面向对象、以及运行时的功能
运行时是指将数据类型的确定由编译时推迟到了运行时
举例:extension和category的区别
平时编写的OC代码,在程序运行的过程中,其实最终会转换成runtime的C语言代码,runtime是OC的幕后工作者
1、category 类别、分类
专门用来给类添加新的方法
不能给类添加成员属性,添加了成员属性,也无法取到
注意:其实可以通过runtime给分类添加属性,即属性关联,重写setter、getter方法
分类中用@property定义变量,只会生成变量的setter、getter方法的声明,不能生成方法实现 和 带下划线的成员变量
2、extension 类扩展
可以说成是特殊的分类,也可称作匿名分类
可以给类添加成员属性,但是是私有变量
可以给类添加方法,也是私有方法
四、方法的本质,sel是什么?IMP是什么?两者之间的关系又是什么?
方法的本质:发送消息,发送消息会有以下几个流程
1.快速查找流程——通过汇编objc_msgSend查找缓存cache_t是否有imp实现
2.慢速查找流程——通过C++中lookUpImpOrForward递归查找当前类和父类的rw中methodlist的方法
3.查找不到消息:动态方法解析——通过调用resolveInstanceMethod和resolveClassMethod来动态方法决议——实现消息动态处理
4.快速转发流程——消息转发流程,forwardingTargetForSelector实现快速转发,由其他对象来实现处理方法
5.慢速转发流程——先调用methodSignatureForSelector获取到方法的签名,生成对应的invocation;再通过forwardInvocation来进行处理
SEL是方法编号,也是方法名,在dyld加载镜像到内存时,通过_read_image方法加载到内存的表中了imp是函数实现指针,找imp就是找函数的过程
SEL和IMP的关系就可以解释为:
sel就相当于本书的目录标题
imp就相当于书本的页码
具体的函数就是具体页码对应的内容
六、[self class]和[super class]的区别以及原理分析
[self class]就是发送消息objc_msgSend,消息接收者是self,方法编号class
[super class]本质就是objc_msgSendSuper,消息的接收者还是self,方法编号class,在运行时,底层调用的是_objc_msgSendSuper2
只是objc_msgSendSuper2会更快,直接跳过self的查找
[self class]方法调用的本质是发送消息,调用class的消息流程,拿到元类的类型,在这里是因为类已经加载到内存,所以在读取时是一个字符串类型,这个字符串类型是在map_images的readClass时已经加入表中,所以打印为TCJStudent
[super class]打印的是TCJStudent,原因是当前的super是一个关键字,在这里只调用objc_msgSendSuper2,其实他的消息接收者和[self class]是一模一样的,所以返回的是TCJStudent
八、Runtime是如何实现weak的,为什么可以自动置nil
十、Method Swizzing坑点
每个类都维护着一个方法列表,即methodList,methodList中有不同的方法即Method,每个方法中包含了方法的sel和IMP,方法交换就是将sel和imp原本的对应断开,并将sel和新的IMP生成对应关系.如下图所示,交换前后的sel和IMP的对应关系

method-swizzling涉及的相关API
通过sel获取方法Method
class_getInstanceMethod:获取实例方法
class_getClassMethod:获取类方法
method_getImplementation:获取一个方法的实现
method_setImplementation:设置一个方法的实现
method_getTypeEncoding:获取方法实现的编码类型
class_addMethod:添加方法实现
class_replaceMethod:用一个方法的实现,替换另一个方法的实现,即aIMP指向bIMP,但是bIMP不一定指向aIMP
method_exchangeImplementations:交换两个方法的实现,即aIMP -> bIMP,bIMP -> aIMP
坑点1:method-swizzling使用过程中的一次性问题
坑点2:子类没有实现,父类实现了
坑点3:子类没有实现,父类也没有实现,下面的调用有什么问题?
method-swizzling的应用
method-swizzling最常用的应用是防止数组、字典等越界崩溃问题在iOS中NSNumber、NSArray、NSDictionary等这些类都是类簇,一个NSArray的实现可能由多个类组成.所以如果想对NSArray进行Swizzling,必须获取到其“真身”进行Swizzling,直接对NSArray进行操作是无效的.
使用Method Swizzling有以下注意事项:
尽可能在+load方法中交换方法
最好使用单例保证只交换一次
自定义方法名不能产生冲突
对于系统方法要调用原始实现,避免对系统产生影响
做好注释(因为方法交换比较绕)
迫不得已情况下才去使用方法交换