runtimeLock.assertLocked(); // GETSECT(_getObjc2NonlazyClassList, classref_t const, "__objc_nlclslist"); // 获取所有 __objc_nlclslist 区的数据(所有非懒加载类) classref_t const *classlist = _getObjc2NonlazyClassList(mhdr, &count); // class +load has been called // #define RW_LOADED (1<<23) // List of classes that need +load called (pending superclass +load) // This list always has superclasses first because of the way it is constructed // 由于其构造方式,此列表始终首先处理 superclasses 的 +load 函数 // 需要调用 +load 的 classes 列表 // static struct loadable_class *loadable_classes = nil;
// 遍历这些非懒加载类,并将其 +load 函数添加到 loadable_classes 数组中,优先添加其父类的 +load 方法, // 用于下面 call_load_methods 函数调用 for (i = 0; i < count; i++) { schedule_class_load(remapClass(classlist[i])); }
// GETSECT(_getObjc2NonlazyCategoryList, category_t * const, "__objc_nlcatlist"); // 获取所有 __objc_nlcatlist 区的数据(所有非懒加载分类) category_t * const *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 if (cls->isSwiftStable()) { _objc_fatal("Swift class extensions and categories on Swift " "classes are not allowed to have +load methods"); } // 如果分类所属的类没有实现就先去实现 realizeClassWithoutSwift(cls, nil); // 断言 ASSERT(cls->ISA()->isRealized()); // List of categories that need +load called (pending parent class +load) // 需要调用 +load 的 categories 列表 // static struct loadable_category *loadable_categories = nil; // 遍历这些分类,并将其 +load 方法添加到 loadable_categories 数组中保存 add_category_to_loadable_list(cat); } }
/*********************************************************************** * prepare_load_methods * Schedule +load for classes in this image, any un-+load-ed * superclasses in other images, and any categories in this image. **********************************************************************/ // Recursively schedule +load for cls and any un-+load-ed superclasses. // cls must already be connected. static void schedule_class_load(Class cls) { // 如果 cls 不存在则 return(下面有一个针对 superclass 的递归调用) if (!cls) return; // DEBUG 模式下的断言,cls 必须是实现过的(这个在 _read_images 中已经实现了) ASSERT(cls->isRealized()); // _read_images should realize // class +load has been called // #define RW_LOADED (1<<23) // RW_LOADED 是 class +load 已被调用的掩码 if (cls->data()->flags & RW_LOADED) return;
// 循环调用 do { // 1. Repeatedly call class +loads until there aren't any more // 调用类中的 +load 函数 while (loadable_classes_used > 0) { // 调用 loadable_classes 中的的类的 +load 函数,并且把 loadable_classes_used 置为 0 call_class_loads(); }
// 3. Run more +loads if there are classes OR more untried categories } while (loadable_classes_used > 0 || more_categories); // 如果 loadable_classes_used 大于 0,或者有更多分类需要调用 +load,则循环继续。(一般 loadable_classes_used 到这里基本就是 0 了) // 自动释放池进行 pop objc_autoreleasePoolPop(pool);
runtimeLock.assertLocked(); // GETSECT(_getObjc2NonlazyClassList, classref_t const, "__objc_nlclslist"); // 获取所有 __objc_nlclslist 区的数据(所有非懒加载类) classref_t const *classlist = _getObjc2NonlazyClassList(mhdr, &count); // class +load has been called // #define RW_LOADED (1<<23) // List of classes that need +load called (pending superclass +load) // This list always has superclasses first because of the way it is constructed // 由于其构造方式,此列表始终首先处理 superclasses 的 +load 函数 // 需要调用 +load 的 classes 列表 // static struct loadable_class *loadable_classes = nil;
// 遍历这些非懒加载类,并将其 +load 函数添加到 loadable_classes 数组中,优先添加其父类的 +load 方法, // 用于下面 call_load_methods 函数调用 for (i = 0; i < count; i++) { schedule_class_load(remapClass(classlist[i])); }
// GETSECT(_getObjc2NonlazyCategoryList, category_t * const, "__objc_nlcatlist"); // 获取所有 __objc_nlcatlist 区的数据(所有非懒加载分类) category_t * const *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 if (cls->isSwiftStable()) { _objc_fatal("Swift class extensions and categories on Swift " "classes are not allowed to have +load methods"); } // 如果分类所属的类没有实现就先去实现 realizeClassWithoutSwift(cls, nil); // 断言 ASSERT(cls->ISA()->isRealized()); // List of categories that need +load called (pending parent class +load) // 需要调用 +load 的 categories 列表 // static struct loadable_category *loadable_categories = nil; // 遍历这些分类,并将其 +load 方法添加到 loadable_categories 数组中保存 add_category_to_loadable_list(cat); } }
/*********************************************************************** * prepare_load_methods * Schedule +load for classes in this image, any un-+load-ed * superclasses in other images, and any categories in this image. **********************************************************************/ // Recursively schedule +load for cls and any un-+load-ed superclasses. // cls must already be connected. static void schedule_class_load(Class cls) { // 如果 cls 不存在则 return(下面有一个针对 superclass 的递归调用) if (!cls) return; // DEBUG 模式下的断言,cls 必须是实现过的(这个在 _read_images 中已经实现了) ASSERT(cls->isRealized()); // _read_images should realize // class +load has been called // #define RW_LOADED (1<<23) // RW_LOADED 是 class +load 已被调用的掩码 if (cls->data()->flags & RW_LOADED) return;
// 循环调用 do { // 1. Repeatedly call class +loads until there aren't any more // 调用类中的 +load 函数 while (loadable_classes_used > 0) { // 调用 loadable_classes 中的的类的 +load 函数,并且把 loadable_classes_used 置为 0 call_class_loads(); }
// 3. Run more +loads if there are classes OR more untried categories } while (loadable_classes_used > 0 || more_categories); // 如果 loadable_classes_used 大于 0,或者有更多分类需要调用 +load,则循环继续。(一般 loadable_classes_used 到这里基本就是 0 了) // 自动释放池进行 pop objc_autoreleasePoolPop(pool);
// 标记处理完成了,可以进行下一个了 loading = NO; }
不停调用类的 +load 方法,直到 loadable_classes 为空。
然后调用一次 call_category_loads 加载分类。
如果有 loadable_classes 或者更多的分类,继续调用 +load 方法。
类先于分类调用。
其中 call_class_loads 会从一个待加载的类列表 loadable_classes 中寻找对应的类,然后通过对应的 SEL ,找到 IMP 的实现并执行。
/*********************************************************************** * lookUpImpOrForward. * The standard IMP lookup. * Without LOOKUP_INITIALIZE: tries to avoid +initialize (but sometimes fails) * Without LOOKUP_CACHE: skips optimistic unlocked lookup (but uses cache elsewhere) * Most callers should use LOOKUP_INITIALIZE and LOOKUP_CACHE * inst is an instance of cls or a subclass thereof, or nil if none is known. * If cls is an un-initialized metaclass then a non-nil inst is faster. * May return _objc_msgForward_impcache. IMPs destined for external use * must be converted to _objc_msgForward or _objc_msgForward_stret. * If you don't want forwarding at all, use LOOKUP_NIL. **********************************************************************/ IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior) { Class curClass; IMP methodPC = nil; Method meth; bool triedResolver = NO;
methodListLock.assertUnlocked();
// Optimistic cache lookup if (behavior & LOOKUP_CACHE) { methodPC = _cache_getImp(cls, sel); if (methodPC) goto out_nolock; }
// Check for freed class if (cls == _class_getFreedObjectClass()) return (IMP) _freedHandler;
// Check for +initialize if ((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized()) { initializeNonMetaClass (_class_getNonMetaClass(cls, inst)); // If sel == initialize, initializeNonMetaClass will send +initialize // and then the messenger will send +initialize again after this // procedure finishes. Of course, if this is not being called // from the messenger then it won't happen. 2778172 }
// The lock is held to make method-lookup + cache-fill atomic // with respect to method addition. Otherwise, a category could // be added but ignored indefinitely because the cache was re-filled // with the old value after the cache flush on behalf of the category. retry: methodListLock.lock();
// Try this class's cache.
methodPC = _cache_getImp(cls, sel); if (methodPC) goto done;
curClass = cls; while ((curClass = curClass->superclass)) { // Superclass cache. meth = _cache_getMethod(curClass, sel, _objc_msgForward_impcache); if (meth) { if (meth != (Method)1) { // Found the method in a superclass. Cache it in this class. log_and_fill_cache(cls, curClass, meth, sel); methodPC = method_getImplementation(meth); goto done; } else { // Found a forward:: entry in a superclass. // Stop searching, but don't cache yet; call method // resolver for this class first. break; } }
/*********************************************************************** * class_initialize. Send the '+initialize' message on demand to any * uninitialized class. Force initialization of superclasses first. **********************************************************************/ void initializeNonMetaClass(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()) { initializeNonMetaClass(supercls); } // Try to atomically set CLS_INITIALIZING. SmallVector<_objc_willInitializeClassCallback, 1> localWillInitializeFuncs; { monitor_locker_t lock(classInitLock); if (!cls->isInitialized() && !cls->isInitializing()) { cls->setInitializing(); reallyInitialize = YES;
// Grab a copy of the will-initialize funcs with the lock held. localWillInitializeFuncs.initFrom(willInitializeFuncs); } } 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);
if (MultithreadedForkChild) { // LOL JK we don't really call +initialize methods after fork(). performForkChildInitialize(cls, supercls); return; } for (auto callback : localWillInitializeFuncs) callback.f(callback.context, 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: thread %p: calling +[%s initialize]", objc_thread_self(), cls->nameForLogging()); }
// Exceptions: A +initialize call that throws an exception // is deemed to be a complete and successful +initialize. // // Only __OBJC2__ adds these handlers. !__OBJC2__ has a // bootstrapping problem of this versus CF's call to // objc_exception_set_functions(). #if __OBJC2__ @try #endif { callInitialize(cls);
if (PrintInitializing) { _objc_inform("INITIALIZE: thread %p: finished +[%s initialize]", objc_thread_self(), cls->nameForLogging()); } } #if __OBJC2__ @catch (...) { if (PrintInitializing) { _objc_inform("INITIALIZE: thread %p: +[%s initialize] " "threw an exception", objc_thread_self(), cls->nameForLogging()); } @throw; } @finally #endif { // Done initializing. lockAndFinishInitializing(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 if (!MultithreadedForkChild) { waitForInitializeToComplete(cls); return; } else { // We're on the child side of fork(), facing a class that // was initializing by some other thread when fork() was called. _setThisThreadIsInitializingClass(cls); performForkChildInitialize(cls, supercls); } } 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!"); } }
如果存在父类,并且父类没有初始化,通过递归初始化父类。
1 2 3 4
supercls = cls->superclass; if (supercls && !supercls->isInitialized()) { initializeNonMetaClass(supercls); }
// 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 if (!MultithreadedForkChild) { waitForInitializeToComplete(cls); return; } else { // We're on the child side of fork(), facing a class that // was initializing by some other thread when fork() was called. _setThisThreadIsInitializingClass(cls); performForkChildInitialize(cls, supercls); }