和上篇文章手把手带你探索Category底层原理同样,直接打开objc
源码,继续来到_objc_init
函数数组
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);
}
复制代码
load_images
是dyld初始化加载image方法,因此此次应该探索这个方法void load_images(const char *path __unused, const struct mach_header *mh) {
// Return without taking locks if there are no +load methods here.
if (!hasLoadMethods((const headerType *)mh)) return;
recursive_mutex_locker_t lock(loadMethodLock);
// Discover load methods
{
mutex_locker_t lock2(runtimeLock);
/** 准备 */
prepare_load_methods((const headerType *)mh);
}
// Call +load methods (without runtimeLock - re-entrant)
call_load_methods();
}
复制代码
load
方法,先去探索prepare_load_methods
作了什么,等会再去看call_load_methods
void prepare_load_methods(const headerType *mhdr) {
size_t count, i;
runtimeLock.assertLocked();
//从 Macho 文件加载类的列表
classref_t *classlist =
_getObjc2NonlazyClassList(mhdr, &count);
for (i = 0; i < count; i++) {
//数组:[<cls,method>,<cls,method>,<cls,method>] 有顺序
schedule_class_load(remapClass(classlist[i]));
}
//针对分类的操做!
category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
for (i = 0; i < count; i++) {
category_t *cat = categorylist[i];
Class cls = remapClass(cat->cls);
if (!cls) continue; // category for ignored weak-linked class
realizeClass(cls);
assert(cls->ISA()->isRealized());
add_category_to_loadable_list(cat);
}
}
复制代码
getObjc2NonlazyClassList
从Mach-O
文件里获取了非懒加载的类列表,而后循环类列表,调用了一个递归方法schedule_class_load
schedule_class_load
干了什么
schedule_class_load
是递归调用父类,一直往上找父类并调用,因此这里论证了咱们文章开头的第一条结论:类的load方法在全部父类的load方法调用以后调用add_class_to_loadable_list
//针对分类的操做!
category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
for (i = 0; i < count; i++) {
category_t *cat = categorylist[i];
Class cls = remapClass(cat->cls);
if (!cls) continue; // category for ignored weak-linked class
realizeClass(cls);
assert(cls->ISA()->isRealized());
add_category_to_loadable_list(cat);
}
复制代码
能够看到分类也是从Mach-O
文件中得到的非懒加载分类,这里刚好验证了分类的load方法的调用顺序和编译顺序有关
,编译顺序不一样,load方法调用的顺序不一样函数
add_category_to_loadable_list
再看看这个方法作了什么 post
这里和上面的add_class_to_loadable_list
相似,只是换成加载到了分类的全局容器中spa
至此,整个prepare_load_methods
探索完了,再回头看看call_load_methods
作了什么 ssr
能够看到,这里是先调用类的load方法,再调用了分类的load方法,正好验证了开头的结论二: 分类的load方法在当前类的load方法调用以后调用3d
call_class_loads
就是经过load的SEL
调用该方法 code
call_category_loads
同理 cdn