+load +initialize
+load方法
在app啟動的時候各個類的+load方法都會被調用,+load方法不是通過消息機制調用的,它是直接調用的,因此無論是在子類或者category中復寫此方法,復寫的+load方法都會被調用,查看runtime的代碼可知調用的順序為
父類->子類->分類。(原因是runtime會把所有類的+load方法放到一個列表中,然后按順序調用,所有category的+load方法放到一個列表中,然后也按順序調用,所以當所有類的+load方法都執行完成后才開始去執行分類的+load方法)。所有類的+load方法在調用列表中的順序由兩個因素決定,一個是此類文件的編譯順序,一個是遞歸調用的順序,即從父類到子類。所有分類的+load方法在調用列表中的順序只由編譯順序決定。
?
schedule_class_load
call_class_load
?
runtime代碼如下:
static void schedule_class_load(Class cls)
{
? ? if (!cls) return;
? ? assert(cls->isRealized());? // _read_images should realize
?
? ? if (cls->data()->flags & RW_LOADED) return;
?
? ? // Ensure superclass-first ordering
? ? schedule_class_load(cls->superclass);
?
? ? add_class_to_loadable_list(cls);
? ? cls->setInfo(RW_LOADED);?
}
?
?
prepare_load_methods
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) {
? ? ? ? ? ? call_class_loads();
? ? ? ? }
?
? ? ? ? // 2. Call category +loads ONCE
? ? ? ? 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;
}
?
?
+initialize
與+load方法不同,+initialize方法是通過消息的方式發送的(msgSend),所以+initialize方法可以被子類或者分類覆蓋,每個類第一次被用到的時候,runtime都會調用 _class_initialize(Class cls)方法,_class_initialize(Class cls)也是一個遞歸調用的方法,當發現cls的父類沒有調用此方法時,會遞歸調用_class_initialize(cls->supercls),調用時會向該類發送initialize消息,此方法被調用完成后cls->isInitialized()這個屬性會變成true。
注意這里存在一個類的initialize方法被調用多次的可能。當子類沒有實現initialize方法時,父類的initialize方法可能被調用多次。
舉個例子:
有兩個類:Person,Girl,Girl繼承Person
如果只有Person實現了initialize方法,那么當這Girl類被用到時,Person的這個initialize方法會被調用兩次,一次是父類調用_class_initialize(Person)時發送的,另一次是調用_class_initialize(Girl)時發送的,因為給Girl發送initialize的時候發現Girl并沒有實現此方法,所以此方法被轉發到了Girl的父類,即Person的類對象。
?
可以這么理解,每個類對應的_class_initialize(Class cls)這個方法只會被調用一次,調用的順序為從父類到子類,在_class_initialize(Class cls)這個方法中會向當前的類對象發送initialize方法。如果當前類沒有實現initialize方法則依次去父類找。
?
_class_initialize(Class cls)
?
void _class_initialize(Class cls)
{
? ? assert(!cls->isMetaClass());
?
? ? Class supercls;
? ? BOOL reallyInitialize = NO;
?
? ? // Make sure super is done initializing BEFORE beginning to initialize cls.
? ? // See note about deadlock above.
? ? supercls = cls->superclass;
? ? if (supercls? &&? !supercls->isInitialized()) {
? ? ? ? _class_initialize(supercls);
? ? }
?? ?
? ? // Try to atomically set CLS_INITIALIZING.
? ? {
? ? ? ? monitor_locker_t lock(classInitLock);
? ? ? ? if (!cls->isInitialized() && !cls->isInitializing()) {
? ? ? ? ? ? cls->setInitializing();
? ? ? ? ? ? reallyInitialize = YES;
? ? ? ? }
? ? }
?? ?
? ? if (reallyInitialize) {
? ? ? ? // We successfully set the CLS_INITIALIZING bit. Initialize the class.
?? ? ? ?
? ? ? ? // Record that we're initializing this class so we can message it.
? ? ? ? _setThisThreadIsInitializingClass(cls);
?? ? ? ?
? ? ? ? // Send the +initialize message.
? ? ? ? // Note that +initialize is sent to the superclass (again) if?
? ? ? ? // this class doesn't implement +initialize. 2157218
? ? ? ? if (PrintInitializing) {
? ? ? ? ? ? _objc_inform("INITIALIZE: calling +[%s initialize]",
?? ? ? ? ? ? ? ? ? ? ? ? cls->nameForLogging());
? ? ? ? }
?
? ? ? ? ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize);
?
? ? ? ? if (PrintInitializing) {
? ? ? ? ? ? _objc_inform("INITIALIZE: finished +[%s initialize]",
?? ? ? ? ? ? ? ? ? ? ? ? cls->nameForLogging());
? ? ? ? } ? ? ? ?
?? ? ? ?
? ? ? ? // Done initializing.?
? ? ? ? // If the superclass is also done initializing, then update?
? ? ? ? // ? the info bits and notify waiting threads.
? ? ? ? // If not, update them later. (This can happen if this +initialize?
? ? ? ? // ? was itself triggered from inside a superclass +initialize.)
? ? ? ? monitor_locker_t lock(classInitLock);
? ? ? ? if (!supercls? ||? supercls->isInitialized()) {
? ? ? ? ? ? _finishInitializing(cls, supercls);
? ? ? ? } else {
? ? ? ? ? ? _finishInitializingAfter(cls, supercls);
? ? ? ? }
? ? ? ? return;
? ? }
?? ?
? ? else if (cls->isInitializing()) {
? ? ? ? // We couldn't set INITIALIZING because INITIALIZING was already set.
? ? ? ? // If this thread set it earlier, continue normally.
? ? ? ? // If some other thread set it, block until initialize is done.
? ? ? ? // It's ok if INITIALIZING changes to INITIALIZED while we're here,?
? ? ? ? // ? because we safely check for INITIALIZED inside the lock?
? ? ? ? // ? before blocking.
? ? ? ? if (_thisThreadIsInitializingClass(cls)) {
? ? ? ? ? ? return;
? ? ? ? } else {
? ? ? ? ? ? monitor_locker_t lock(classInitLock);
? ? ? ? ? ? while (!cls->isInitialized()) {
? ? ? ? ? ? ? ? classInitLock.wait();
? ? ? ? ? ? }
? ? ? ? ? ? return;
? ? ? ? }
? ? }
?? ?
? ? else if (cls->isInitialized()) {
? ? ? ? // Set CLS_INITIALIZING failed because someone else already?
? ? ? ? // ? initialized the class. Continue normally.
? ? ? ? // NOTE this check must come AFTER the ISINITIALIZING case.
? ? ? ? // Otherwise: Another thread is initializing this class. ISINITIALIZED?
? ? ? ? // ? is false. Skip this clause. Then the other thread finishes?
? ? ? ? // ? initialization and sets INITIALIZING=no and INITIALIZED=yes.?
? ? ? ? // ? Skip the ISINITIALIZING clause. Die horribly.
? ? ? ? return;
? ? }
?? ?
? ? else {
? ? ? ? // We shouldn't be here.?
? ? ? ? _objc_fatal("thread-safe class init in objc runtime is buggy!");
? ? }
}
?
轉載于:https://www.cnblogs.com/yibinpan/p/9693184.html
總結
以上是生活随笔為你收集整理的+load +initialize的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 六味地黄丸哪个品牌的好
- 下一篇: Bootstrap4.x 新增
