深入了解category
extension看起来像是一个匿名的category,但是extension和有名字的category几乎完全是两个东西
extension在编译期决议,它就是类的一部分,在编译期和头文件里面的@interface以及实现文件里面的@implement一起形成一个完整的类,它伴随的产生而产生,消失而消失。extension一般用来隐藏类的私有消息,你必须有一个类的源码才能为一个类添加extension,所以你无法为系统的类添加extension。
category在运行期决议的
extension可以添加实例变量,而category是无法使用实例变量的。因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局。
Objective-C 对象都是 C 语言结构体实现的。在runtime层,category结构体
文章图片
image.png 1、类的名字
这里看到对name的修饰是用的const,所以扩充类的名字不可以重复,不然在编译阶段的时候会编译错误。
2、类
文章图片
image.png 这里指出扩展类并不是被扩充类的重新映射
3、
struct method_list_t *instanceMethods;
//类方法列表
struct method_list_t *classMethods;
//实例方法列表
struct protocol_list_t *protocols;
//category中实现的协议的列表
struct property_list_t *instanceProperties;
//实例属性列表
struct property_list_t *_classProperties;
//类属性列表
4、
method_list_t
文章图片
image.png
从注释和里面的一些逻辑来简单推测,这个修饰的对象其实只是作为一个标识符的存在,标记对应的方法列表在方法map上的位置。
5、
从源码数据结构的定义来看缺少了实例变量相关的描述,这也解释了为啥category无法添加实例变量。但是OC作为一个动态语言,所有的方法名对象声明都是在编译期组织排列好,在运行的过程中再去寻找转发所对应的实现。如果想要实现在category中添加实例变量,少年,runtime了解一下?
回到category
如果category中有与被扩展类相同的方法,调用的时候则会调用到category里面的这个方法。实际上category的方法没有“完全替换”原来的方法,如果category和原有类都有method A ,那么category附加完成之后,类的方法列表里就会有两个method A。但是在运行调用过程中,category的method A会排在方法列表更前,runtime在找到第一个符合的方法的时候就把它给return回去了,这就造成了“覆盖”的一种感觉。
category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面。那如果说是两个category拥有相同的方法呢?这样又是谁的会先被调用?同样的,这取决于编译排列的先后。
【深入了解category】
如果想要修改调用的顺序的话,只需要
文章图片
image.png
修改Compile Sources中的category文件顺序就可以了,但是作为被扩充的类,也就是你所扩充的类无论怎么去调整顺序,它一定是会在category之前加载,也就是+load()方法一定是第一个走到的,然后才依次去加载扩充类,然后最后加载的扩充里面的方法会是最先被找到的。
推荐阅读
- 深入理解Go之generate
- 我们重新了解付费。
- 拍照一年啦,如果你想了解我,那就请先看看这篇文章
- C语言中的时间函数clock()和time()你都了解吗
- 【1057快报】深入机关,走下田间,交通普法,共创文明
- 操作系统|[译]从内部了解现代浏览器(1)
- 生发知识,带你深入了解
- 深入理解|深入理解 Android 9.0 Crash 机制(二)
- 了解自然大气粒子对气候的影响
- 深入浅出谈一下有关分布式消息技术(Kafka)