什么是category
- category是Objective-C 2.0之后添加的语言特性,主要作用是为已经存在的类添加方法。
category的好处
- 可以减少单个文件的体积,便于查找
- 可以把不同的功能组织到不同的category中区
- 可以按需加载,声明私有方法,把framework的私有方法公开
category的数据结构
category是如何被加载的
- dyld是苹果的动态加载器,用来加载image(Mach-O格式的二进制文件)
- 当程序启动时,系统内核首先会加载dyld,而dyld会将我们App所依赖的各种库加载到内存空间中,其中就包括libobjc库(OC和runtime),这些工作是在main函数之前完成的
- _objc_init是Objective-C runtime的入口函数,这里面主要的功能是读取Mach-O文件OC对应的Segment section,并根据其中的数据代码信息,完成对OC的内存布局,以及初始化runtime相关的数据结构
category加载分析
- 找到runtime的入口函数,_objc_init注册了三个函数,当mach-O二进制文件映射进内存的时候执行map_images回调函数,当mach-O二进制文件初始化的时候调用load_images(load方法也是这时候被加载的),当mach-O二进制文件被移除的时候执行unmap_image函数
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init();
tls_init();
static_init();
lock_init();
exception_init();
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
- map_images函数点进去,开始读取mach-O二进制文件
- Discover categories.
category_t **catlist = _getObjc2CategoryList(hi, &count);
// 读取__objc_catlist字段下所有的category
GETSECT(_getObjc2CategoryList, category_t *, "__objc_catlist");
// 将分类和当前类建立绑定关系
addUnattachedCategoryForClass(cat, cls, hi);
- 调用remethodizeClass对当前类进行重新排列,调用attachCategories将分类中的内容附加到当前类中
- 把要添加到原来类的方法列表中的方法准备好
prepareMethodLists(cls, mlists, mcount, NO, fromBundle); rw->methods.attachLists(mlists, mcount);
- 将分类中的方法添加到原来类的方法列表中,调用memmove,memcpy,移动当前类的内存空间,为当前类腾出内存空间,存放分类当中方法列表