iOS 分类源码解读
分类的好处
用分类声明一些私有方法;
分类一些体积庞大的类文件,eg: AppDelegate, 组织代码更灵活
把 framework 的私有方法公开
分类的特点
- 运行时决议, 在 runtime 添加到类中, 在编辑的时候分类会将分类方法作为一个数组,动态的添加到宿主类中, 如果存在同名的扩展方法, 那么最后一个参与编译的方法生效并覆盖之前的同名方法(但是还是实际存在的,不过优先级没有分类中的高), 但是可以通过一些代码决定调用最后一个参与编译的方法还是调用其他同名方法
memcopy(array->lists, addedLists,addedCount *sizeof*array()->lists[0])) 覆盖宿主 方法的原因,
; - 为系统类添加分类
- 名字相同的分类会引起编译报错
分类中可以添加哪些内容
- 可以添加实例方法
- 类方法
- 协议
- 属性 只声明了 set get , 并没有在分类中添加实例变量
- 添加分类的实例变量, 需要通过关联对象进行设置
分类的结构体构成
1 | //分类文件 |
分类的加载调用栈
_objec_init
入口调用map_2_images
数据镜像映射之类的吧, 我也不怎么懂map_images_nolock
数据镜像映射之类的吧, 我也不怎么懂read_images
objec 源代码中, map_images_noloc会调用此方法, 将读取到的数据镜像,将解析到的信息(方法和协议)传递给remethodizeClass
(猜的), 添加到类和类的元类上remethodizeClass
整合class 中的所有分类, 进行操作;
此过程会将分类的属性,协议,方法都添加到类中;
下面会有详细的说明关于分类是如何加载的1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16static void remethodizeClass(Class cls)
{
category_list *cats;
bool isMeta;
runtimeLock.assertWriting();
isMeta = cls->isMetaClass();
[ // Re-methodizing: check for more categories]
if ((cats = unattachedCategoriesForClass(cls, false/*not realizing*/))) {
if (PrintConnecting) {
[ _objc_inform("CLASS: attaching categories to class '%s' %s", ]
cls->nameForLogging(), isMeta ? "(meta)" : "");
}
attachCategories(cls, cats, true /*flush caches*/);
free(cats);
}
}
分类是如何加载的
方法覆盖
我们上面说了一些category
原理, 如果存在同名方法的话, 宿主类中的方法会被覆盖掉, 那么我们如何调用宿主类中被覆盖的方法呢?
刚才说了, 并不是被覆盖掉了, 而是优先级的问题, 我们只要顺着方法列表找到最后一个对应名字的方法就可以啦~
1 | Class currentClass = [MyClass class]; |
通过关联对象给分类添加成员变量
关联对象由AssociationsManager
管理并在 AssociationsHashMap
中存储;AssociationsHashMap
是一个全局容器, 通过一个映射表来操作到具体不同的类
1 | #import "MyClass.h" |
关联对象实现原理
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.