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