有load方法。web
load方法在runtime加載類、分類的時候調用,調用方式是直接調用方法,而不是經過消息機制觸發調用。編輯器
load
方法能夠繼承,可是通常狀況下不會主動去調用load方法,都是讓系統自動調用。函數
先調用類的load
方法。ui
按照編譯前後順序調用,先編譯的先調用。url
調用子類的load
方法以前會先調用父類的load
方法。spa
再調用分類的load
方法。ssr
按照編譯前後順序調用,先編譯的先調用。code
// objc-os.mm/_objc_init(void)
void _objc_init(void) { _dyld_objc_notify_register(&map_images, load_images, unmap_image); } // objc-runtime-new.mm/load_images void load_images(const char *path __unused, const struct mach_header *mh) { prepare_load_methods((const headerType *)mh); call_load_methods(); } // objc-runtime-new.mm / prepare_load_methods void prepare_load_methods(const headerType *mhdr) { size_t count, i; runtimeLock.assertWriting(); //獲取全部的類 classref_t *classlist = _getObjc2NonlazyClassList(mhdr, &count); for (i = 0; i < count; i++) { // 整理要調用load方法的類 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); } } // objc-runtime-new.mm / schedule_class_load static void schedule_class_load(Class cls) { if (!cls) return; assert(cls->isRealized()); // _read_images should realize //類是否已經被加載到loadable_classes if (cls->data()->flags & RW_LOADED) return; // 確保父類排在前面 schedule_class_load(cls->superclass); add_class_to_loadable_list(cls); // 標誌該類已經添加到了loadable_classes cls->setInfo(RW_LOADED); } // objc-loadmethod.mm / add_class_to_loadable_list void add_class_to_loadable_list(Class cls) { IMP method; loadMethodLock.assertLocked(); method = cls->getLoadMethod(); if (!method) return; // Don't bother if cls has no +load method if (PrintLoading) { _objc_inform("LOAD: class '%s' scheduled for +load", cls->nameForLogging()); } if (loadable_classes_used == loadable_classes_allocated) { loadable_classes_allocated = loadable_classes_allocated*2 + 16; loadable_classes = (struct loadable_class *) realloc(loadable_classes, loadable_classes_allocated * sizeof(struct loadable_class)); } loadable_classes[loadable_classes_used].cls = cls; loadable_classes[loadable_classes_used].method = method; loadable_classes_used++; } //objc-loadmethod.mm / call_load_methods void call_load_methods(void) { static bool loading = NO; bool more_categories; loadMethodLock.assertLocked(); // Re-entrant calls do nothing; the outermost call will finish the job. if (loading) return; loading = YES; void *pool = objc_autoreleasePoolPush(); do { // 1. Repeatedly call class +loads until there aren't any more while (loadable_classes_used > 0) { //調用類的load方法 call_class_loads(); } // 2. Call category +loads ONCE // 調用Category的load方法 more_categories = call_category_loads(); // 3. Run more +loads if there are classes OR more untried categories } while (loadable_classes_used > 0 || more_categories); objc_autoreleasePoolPop(pool); loading = NO; } //objc-loadmethod.mm / call_class_loads static void call_class_loads(void) { int i; // Detach current loadable list. struct loadable_class *classes = loadable_classes; int used = loadable_classes_used; loadable_classes = nil; loadable_classes_allocated = 0; loadable_classes_used = 0; // Call all +loads for the detached list. for (i = 0; i < used; i++) { Class cls = classes[i].cls; // 取出load方法 load_method_t load_method = (load_method_t)classes[i].method; if (!cls) continue; if (PrintLoading) { _objc_inform("LOAD: +[%s load]\n", cls->nameForLogging()); } //調用load方法。 (*load_method)(cls, SEL_load); } // Destroy the detached list. if (classes) free(classes); } 複製代碼
initialize
會在類第一次接受到消息的時候調用。與load
方法不一樣的是initialize
是經過消息機制調用的即經過objc_msgsend()
調用。orm
根據調用順序觸發。繼承
調用子類的initialize
會先觸發父類的initialize
。
// objc-runtime-new.mm / class_getInstanceMethod
Method class_getInstanceMethod(Class cls, SEL sel) { if (!cls || !sel) return nil; lookUpImpOrNil(cls, sel, nil, NO/*initialize*/, NO/*cache*/, YES/*resolver*/); return _class_getMethod(cls, sel); } // objc-runtime-new.mm / lookUpImpOrNil IMP lookUpImpOrNil(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver) { IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver); if (imp == _objc_msgForward_impcache) return nil; else return imp; } // objc-runtime-new.mm / lookUpImpOrForward IMP lookUpImpOrForward(Class cls, SEL sel, id inst, bool initialize, bool cache, bool resolver) { IMP imp = nil; runtimeLock.read(); if (initialize && !cls->isInitialized()) { runtimeLock.unlockRead(); _class_initialize (_class_getNonMetaClass(cls, inst)); runtimeLock.read(); } return imp; } // objc-initialize.mm / _class_initialize void _class_initialize(Class cls) { assert(!cls->isMetaClass()); supercls = cls->superclass; // 遞歸調用,先調用父類的 initialize if (supercls && !supercls->isInitialized()) { _class_initialize(supercls); } callInitialize(cls); } // objc-initialize.mm / callInitialize void callInitialize(Class cls) { // 經過 objc_msgSend 進行調用 ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize); asm(""); } 複製代碼
調用方式
調用時刻
load、initialize的調用順序?
load
再調用分類的load
initialize