和上篇文章手把手带你探索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方法调用的顺序不一样markdown
add_category_to_loadable_list
再看看这个方法作了什么 函数
这里和上面的add_class_to_loadable_list
相似,只是换成加载到了分类的全局容器中post
至此,整个prepare_load_methods
探索完了,再回头看看call_load_methods
作了什么 spa
能够看到,这里是先调用类的load方法,再调用了分类的load方法,正好验证了开头的结论二: 分类的load方法在当前类的load方法调用以后调用ssr
call_class_loads
就是经过load的SEL
调用该方法 code
call_category_loads
同理 orm