和上篇文章手把手帶你探索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