category的实现原理
编译之后,category在内存中的结构体为 category_t ,编译器会把该类的所有分类依次编译为 category_t 类型的结构体,结构体中包含对象方法列表、类方法列表、协议列表、属性列表等,编译时,并不进行结构体合并,在内存中是独立存在的。
通过runtime的动态特性,在程序运行时,将分类结构体中的对象方法、协议、属性 合并进类对象中,将类方法合并进元类对象中,“合并”,实际上是在内存中,对数据进行内存移动memmove 和 memcpy
memmove 是根据传入的数据内存大小,从哪开始移动,中间是有一个判断的,是向左挪动还是向右挪动(可以保证数据的完整性);而 memcpy 不判断,它是从最小的内存开始逐一复制移动,将分类中的数据插入到原来数据前面
进行内存移动的时候,memmove 不会造成内存覆盖;从新的地方进行内存移动的时候,使用 memcpy 比较合适,因为它不需要管数据是否会内存覆盖
category的加载处理过程
1.通过RunTime加载某个类的所有Category数据
2.把所有的category方法,属性,协议数据合并到一个大数组中,后面参与的category数据,会被加到数组前面
3.将合并的分类数据(方法,属性,协议),插入到原来数据的前面
Category 和 Extension(匿名分类) 的区别
Class-Extension 在编译阶段,它的数据就已经加载到了类信息中(类 对象、元类对象),而Class-Category是在运行时,才将数据合并到类信息中。
Category 中load方法什么时候调用?load方法能继承吗?
load方法会在runtime加载类和分类的时候调用。
调用顺序:1.先调用类的+load,按照编译先后顺序调用(先编译,先调用)调用子类的+load之前会先调用父类的+load;2.再调用分类的+load,按照编译先后顺序调用(先编译,先调用)
load能继承,但是一般情况下不主动去调用load方法,都是让系统自己去调用。
load,initialize的方法区别是什么?它们在Category中的调用顺序?以及出现继承时他们之间的调用过程?
调用方式
load,根据函数地址直接调用(IMP)。initialize,通过objc_msgSend调用,类第一次接收到消息的时候调用
调用时机
load,runtime加载类、分类的时候调用(只调用一次)。initialize,类第一次收到消息的时候调用,每个类只会调用一次(父类的+initialize 可能会被调用多次)
调用顺序
load,先调用类的+load(先编译先调用,调用子类load之前先调用父类的load),再调用分类的+load。initialize,先调用父类的+initialize,再调用自己的+initialize
继承出现时,调用子类load之前先调用父类的load,先调用父类的+initialize,再调用自己的+initialize
网友评论