在启动 app
的时候, dyld
会对动态库进行加载、链接等一系列动作,之后就会来到 libobjc.A.dylib
库中调用 _objc_init
对类进行处理,通过 map_images
映射出整个镜像文件,再通过 read_images
加载镜像文件,此时类已经加载完成,那其中类的加载的流程又是怎么样的呢?类的属性、方法、协议都是怎么加载的呢?接下来就从 _objc_init
开始整篇文章的分析。附上 objc 源码 下载链接。
void _objc_init(void) { static bool initialized = false; if (initialized) return; initialized = true; // 环境变量的一些操作 environ_init(); tls_init(); // 系统级别的 c++ 构造函数调用 static_init(); // 空函数,预留 lock_init(); // 注册监听异常的回调 exception_init(); // 注册回调通知 _dyld_objc_notify_register(&map_images, load_images, unmap_image); } 复制代码
environ_init
方法是读取影响运行时的环境变量,最后内部有一段打印环境变量的代码。我将它提取出来,不做判断,打印结果如下。当然也可以在终端使用 export OBJC_HELP=1
指令打印环境变量。
Xcode
中修改环境变量的值来达到我们调试的一些目的。
主要是对线程 key
的绑定。
void tls_init(void) { #if SUPPORT_DIRECT_THREAD_KEYS _objc_pthread_key = TLS_DIRECT_KEY; pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific); #else _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific); #endif } 复制代码
运行 C++
静态构造函数,在 dyld
调用我们自定义构造函数之前。
static void static_init() { size_t count; auto inits = getLibobjcInitializers(&_mh_dylib_header, &count); for (size_t i = 0; i < count; i++) { inits[i](); } } 复制代码
空函数,猜测可能为了以后做的预留。
void lock_init(void) { } 复制代码
初始化 libobjc
库的异常处理系统,注册监听异常崩溃的回调,当发生崩溃时,就会来到 _objc_terminate
函数里面。
void exception_init(void) { old_terminate = std::set_terminate(&_objc_terminate); } static void _objc_terminate(void) { if (PrintExceptions) { _objc_inform("EXCEPTIONS: terminating"); } if (! __cxa_current_exception_type()) { // No current exception. (*old_terminate)(); } else { // There is a current exception. Check if it’s an objc exception. @try { __cxa_rethrow(); } @catch (id e) { // It’s an objc object. Call Foundation’s handler, if any. (*uncaught_handler)((id)e); (*old_terminate)(); } @catch (...) { // It’s not an objc object. Continue to C++ terminate. (*old_terminate)(); } } } 复制代码
整个 objc
在这个里面是一个运行时环境,运行时环境去加载所有类的一些信息的时候,就会依赖这个注册函数的回调的通知,告诉当前的 dyld
的做了哪些事情,你需要哪些环境来进行彼此的通讯,比如当前的 map_images
。
简单来说就是有没有实现
load
方法,非懒加载类在类的内部实现了load
方法,类的加载就会提前,而懒加载类没有实现load
方法,在使用的第一次才会加载,当我们再给这个类的发送消息,如果是第一次,在消息查找的过程中就会判断这个类是否加载,没有加载就会加载这个类。
map_images
方法在 image
加载到内存的时候会触发该方法的调用。忽略内部函数跳转、打印和操作 hCount
的代码,最终会来到 _read_images
。
_read_images
方法首先创建了两张表用来存储类。// 如果是第一次进来,就会走 if 下面的代码 if (!doneOnce) { // 之后就不会来了 // 为什么只来一次呢,因为第一次进来的时候,类,协议,sel,分类都没有 // 需要创建容器来保存这些东西,这里创建的是两个表。 doneOnce = YES; //... 忽略一些无关紧要的代码 if (DisableTaggedPointers) { disableTaggedPointers(); } // TaggedPointer 的优化处理 initializeTaggedPointerObfuscator(); // 4/3是 NXMapTable 的负载因子 int namedClassesSize = (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3; // 实例化存储类的哈希表,并根据当前类的数量做动态扩容 // 只要你没有在共享缓存的类,不管实现或者未实现都会在这个里面 gdb_objc_realized_classes = NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize); // 已经被分配的类和元类都会放在这个表里 allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil); } 复制代码
readClass
分析for (EACH_HEADER) { // 从编译后的类列表中取出所有类,获取到的是一个classref_t类型的指针 classref_t *classlist = _getObjc2ClassList(hi, &count); if (! mustReadClasses(hi)) { // 图像充分优化,我们不需要调用 readClass() continue; } bool headerIsBundle = hi->isBundle(); bool headerIsPreoptimized = hi->isPreoptimized(); for (i = 0; i < count; i++) { // 数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系统类,例如CF、Fundation、libdispatch中的类。以及自己创建的类 Class cls = (Class)classlist[i]; // 通过 readClass 函数获取处理后的新类,内部主要操作 ro 和 rw 结构体 Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized); // 初始化所有懒加载的类需要的内存空间,并将所有的未来需要处理的类添加到一个数组中 // 现在数据没有加载到的,连类都没有初始化 if (newCls != cls && newCls) { // Class was moved but not deleted. Currently this occurs // only when the new class resolved a future class. // Non-lazily realize the class below. // 将懒加载的类添加到数组中 resolvedFutureClasses = (Class *) realloc(resolvedFutureClasses, (resolvedFutureClassCount+1) * sizeof(Class)); resolvedFutureClasses[resolvedFutureClassCount++] = newCls; } } } Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized) { const char *mangledName = cls->mangledName(); // 如果某个 cls 的 superclass 是 weak-linked 的并且丢失了,则返回YES。 if (missingWeakSuperclass(cls)) { if (PrintConnecting) { _objc_inform("CLASS: IGNORING class '%s' with " "missing weak-linked superclass", cls->nameForLogging()); } // 添加到重映射表里面,映射为 nil addRemappedClass(cls, nil); cls->superclass = nil; return nil; } //... 忽略一些无关紧要的代码 cls->fixupBackwardDeployingStableSwift(); Class replacing = nil; // 对未来的一些类的 ro 和 rw 的特殊处理,一般不会进去 if (Class newCls = popFutureNamedClass(mangledName)) { // 将objc_class复制到future类的结构中 // 保存future 类的 rw class_rw_t *rw = newCls->data(); const class_ro_t *old_ro = rw->ro; memcpy(newCls, cls, sizeof(objc_class)); rw->ro = (class_ro_t *)newCls->data(); newCls->setData(rw); freeIfMutable((char *)old_ro->name); free((void *)old_ro); addRemappedClass(cls, newCls); replacing = cls; cls = newCls; } if (headerIsPreoptimized && !replacing) { // 断言 assert(getClassExceptSomeSwift(mangledName)); } else { // 将 cls 加入到 gdb_objc_realized_classes 表里面去 addNamedClass(cls, mangledName, replacing); // 将 cls 插入到 allocatedClasses 表里面去 addClassTableEntry(cls); } // 供以后参考:共享缓存从不包含mh_bundle if (headerIsBundle) { cls->data()->flags |= RO_FROM_BUNDLE; cls->ISA()->data()->flags |= RO_FROM_BUNDLE; } // 到此时,这个类在整个表里就有了,返回 return cls; } 复制代码
remapClassRef
// 主要是修复重映射 - !noClassesRemapped() 在这里为 false,所以一般走不进来 // 将未映射Class和Super Class重映射,被remap的类都是非懒加载的类 if (!noClassesRemapped()) { for (EACH_HEADER) { // 重映射Class,注意是从_getObjc2ClassRefs函数中取出类的引用 Class *classrefs = _getObjc2ClassRefs(hi, &count); for (i = 0; i < count; i++) { remapClassRef(&classrefs[i]); } // fixme why doesn’t test future1 catch the absence of this? classrefs = _getObjc2SuperRefs(hi, &count); for (i = 0; i < count; i++) { remapClassRef(&classrefs[i]); } } } 复制代码
sel_registerNameNoLock
// 将所有SEL都注册到哈希表中,是另外一张哈希表 static size_t UnfixedSelectors; { mutex_locker_t lock(selLock); for (EACH_HEADER) { if (hi->isPreoptimized()) continue; bool isBundle = hi->isBundle(); SEL *sels = _getObjc2SelectorRefs(hi, &count); UnfixedSelectors += count; for (i = 0; i < count; i++) { // sel_cname 将 SEL 强转为 char 类型 const char *name = sel_cname(sels[i]); // 注册 SEL 的操作 sels[i] = sel_registerNameNoLock(name, isBundle); } } } 复制代码
fixupMessageRef
// 修复旧的函数指针调用遗留 for (EACH_HEADER) { message_ref_t *refs = _getObjc2MessageRefs(hi, &count); if (count == 0) continue; if (PrintVtables) { _objc_inform("VTABLES: repairing %zu unsupported vtable dispatch " "call sites in %s", count, hi->fname()); } for (i = 0; i < count; i++) { // 内部将常用的 alloc、objc_msgSend 等函数指针进行注册,并 fix 为新的函数指针 fixupMessageRef(refs+i); } } 复制代码
readProtocol
// 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中 for (EACH_HEADER) { extern objc_class OBJC_CLASS_$_Protocol; // cls = Protocol类,所有协议和对象的结构体都类似,isa都对应Protocol类 Class cls = (Class)&OBJC_CLASS_$_Protocol; assert(cls); // 获取protocol哈希表 NXMapTable *protocol_map = protocols(); bool isPreoptimized = hi->isPreoptimized(); bool isBundle = hi->isBundle(); // 从编译器中读取并初始化Protocol protocol_t **protolist = _getObjc2ProtocolList(hi, &count); for (i = 0; i < count; i++) { readProtocol(protolist[i], cls, protocol_map, isPreoptimized, isBundle); } } 复制代码
remapProtocolRef
// 修复协议列表引用,优化后的 images 可能是正确的,但是并不确定 for (EACH_HEADER) { // 需要注意到是,下面的函数是 _getObjc2ProtocolRefs,和上面的 _getObjc2ProtocolList 不一样 protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count); for (i = 0; i < count; i++) { remapProtocolRef(&protolist[i]); } } 复制代码
realizeClassWithoutSwift
分析初始化类就在这一步,首先将非懒加载类从 Mach-O
里面读取出来,然后通过 realizeClassWithoutSwift
实例化 rw
。
// 实现非懒加载的类,对于load方法和静态实例变量 for (EACH_HEADER) { classref_t *classlist = _getObjc2NonlazyClassList(hi, &count); for (i = 0; i < count; i++) { Class cls = remapClass(classlist[i]); if (!cls) continue; //... 忽略一些对 cls 的 cache 的一些操作 addClassTableEntry(cls); //... 忽略无关紧要的代码 // 实现所有非懒加载的类(实例化类对象的一些信息,例如rw) realizeClassWithoutSwift(cls); } } // 遍历 resolvedFutureClasses 数组,实现懒加载的类 // resolvedFutureClasses 数组是在第二步的时候添加懒加载类的 if (resolvedFutureClasses) { for (i = 0; i < resolvedFutureClassCount; i++) { Class cls = resolvedFutureClasses[i]; if (cls->isSwiftStable()) { _objc_fatal("Swift class is not allowed to be future"); } // 实现懒加载的类 realizeClassWithoutSwift(cls); cls->setInstancesRequireRawIsa(false/*inherited*/); } free(resolvedFutureClasses); } static Class realizeClassWithoutSwift(Class cls) { runtimeLock.assertLocked(); const class_ro_t *ro; class_rw_t *rw; Class supercls; Class metacls; bool isMeta; if (!cls) return nil; // 判断 cls 是否已经初始化,里面是对 data()->flags 的判断 if (cls->isRealized()) return cls; assert(cls == remapClass(cls)); // 验证类不在共享缓存的未删除部分 ro = (const class_ro_t *)cls->data(); // 判断类是否是未实现的未来类 if (ro->flags & RO_FUTURE) { // 是未来的类. rw 已经被初始化 rw = cls->data(); ro = cls->data()->ro; // 修改 flags cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE); } else { // 正常的类. 分配可写的类数据。 // 开辟 rw 内存空间 rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1); rw->ro = ro; rw->flags = RW_REALIZED|RW_REALIZING; cls->setData(rw); } // 判断是否是元类 isMeta = ro->flags & RO_META; rw->version = isMeta ? 7 : 0; // old runtime went up to 6 // 为这个类选择一个索引 // 设置cls->instancesRequireRawIsa如果没有更多的索引可用 cls->chooseClassArrayIndex(); if (PrintConnecting) { _objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s", cls->nameForLogging(), isMeta ? " (meta)" : "", (void*)cls, ro, cls->classArrayIndex(), cls->isSwiftStable() ? "(swift)" : "", cls->isSwiftLegacy() ? "(pre-stable swift)" : ""); } // 递归调用,实现父类和元类 supercls = realizeClassWithoutSwift(remapClass(cls->superclass)); metacls = realizeClassWithoutSwift(remapClass(cls->ISA())); #if SUPPORT_NONPOINTER_ISA // 禁用一些类和非指针isa bool instancesRequireRawIsa = cls->instancesRequireRawIsa(); bool rawIsaIsInherited = false; static bool hackedDispatch = false; // 禁用非指针的 isa if (DisableNonpointerIsa) { // 非指针isa禁用的环境或应用程序SDK版本 instancesRequireRawIsa = true; } else if (!hackedDispatch && !(ro->flags & RO_META) && 0 == strcmp(ro->name, "OS_object")) { // 在 hackedDispatch 里 isa 也充当虚表指针 hackedDispatch = true; instancesRequireRawIsa = true; } else if (supercls && supercls->superclass && supercls->instancesRequireRawIsa()) { // 从元类到根元类设置 instancesRequireRawIsa = true; rawIsaIsInherited = true; } if (instancesRequireRawIsa) { cls->setInstancesRequireRawIsa(rawIsaIsInherited); } // SUPPORT_NONPOINTER_ISA #endif // 在重新映射时更新父类和元类 cls->superclass = supercls; cls->initClassIsa(metacls); // 协调实例变量的偏移量/布局,可能会重新分配 class_ro_t,更新我们的 ro 变量。 if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro); // 如果还没有设置就开始设置 fastInstanceSize。 cls->setInstanceSize(ro->instanceSize); // 将一些标志从 ro 复制到 rw if (ro->flags & RO_HAS_CXX_STRUCTORS) { cls->setHasCxxDtor(); if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) { cls->setHasCxxCtor(); } } // 从ro或父类中传播关联的对象禁止标志 if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) || (supercls && supercls->forbidsAssociatedObjects())) { rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS; } // 将这个类连接到它的父类的子类列表,即双向绑定 if (supercls) { addSubclass(supercls, cls); } else { addRootClass(cls); } // 修复 cls 的方法列表、协议列表和属性列表,以及附加任何未完成的类别 methodizeClass(cls); return cls; } 复制代码
methodizeClass
是将 ro
里面的方法、协议以及属性附加到 rw
里面和把分类中的方法、协议和属性添加到本类中,这也是分类是添加到本类中的时机,下面单独讲解一下这个方法。
static void methodizeClass(Class cls) { runtimeLock.assertLocked(); bool isMeta = cls->isMetaClass(); auto rw = cls->data(); auto ro = rw->ro; // 将 ro 里面的方法附加到 rw 里面去 method_list_t *list = ro->baseMethods(); if (list) { prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls)); rw->methods.attachLists(&list, 1); } // 将 ro 里面的属性附加到 rw 里面去 property_list_t *proplist = ro->baseProperties; if (proplist) { rw->properties.attachLists(&proplist, 1); } // 将 ro 里面的协议附加到 rw 里面去 protocol_list_t *protolist = ro->baseProtocols; if (protolist) { rw->protocols.attachLists(&protolist, 1); } // 根类获得额外的方法实现,如果它们还没有。这些适用于类别替换之前。 if (cls->isRootMetaclass()) { // SEL SEL_initialize = NULL; addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO); } // Attach categories. // 返回类的未附加类别列表,并从列表中删除它们。 category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/); // 将类别中的方法列表、属性和协议附加到类中 attachCategories(cls, cats, false /*don’t flush caches*/); if (cats) free(cats); // ... 忽略一些无关紧要的代码 } 复制代码
其中 attachLists
出现频率很高,基本上方法、协议、属性都是通过 attachLists
函数附加到对应的列表上的,接下来单独介绍一下这个方法。
void attachLists(List* const * addedLists, uint32_t addedCount) { if (addedCount == 0) return; if (hasArray()) { // many lists -> many lists uint32_t oldCount = array()->count; uint32_t newCount = oldCount + addedCount; setArray((array_t *)realloc(array(), array_t::byteSize(newCount))); array()->count = newCount; // // 将 addedLists 移动到 array,memmove会对拷贝的数据作检查,确保内存没有覆盖,如果发现会覆盖数据,简单的实现是调转开始拷贝的位置,从尾部开始拷贝 memmove(array()->lists + addedCount, array()->lists, oldCount * sizeof(array()->lists[0])); // 将 addedLists 拷贝到 array()->lists,如果复制的两个区域存在重叠时使用memcpy,其结果是不可预知的,有可能成功也有可能失败的 memcpy(array()->lists, addedLists, addedCount * sizeof(array()->lists[0])); } else if (!list && addedCount == 1) { // 0 lists -> 1 list list = addedLists[0]; } else { // 1 list -> many lists,直接追到数组后面 List* oldList = list; uint32_t oldCount = oldList ? 1 : 0; uint32_t newCount = oldCount + addedCount; setArray((array_t *)malloc(array_t::byteSize(newCount))); array()->count = newCount; if (oldList) array()->lists[addedCount] = oldList; memcpy(array()->lists, addedLists, addedCount * sizeof(array()->lists[0])); } } 复制代码
addUnattachedCategoryForClass
// 发现和处理所有Category for (EACH_HEADER) { // 外部循环遍历找到当前类,查找类对应的Category数组 category_t **catlist = _getObjc2CategoryList(hi, &count); bool hasClassProperties = hi->info()->hasCategoryClassProperties(); for (i = 0; i < count; i++) { // 内部循环遍历当前类的所有Category category_t *cat = catlist[i]; Class cls = remapClass(cat->cls); if (!cls) { // 类别的目标类丢失(可能是弱链接) catlist[i] = nil; if (PrintConnecting) { _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with " "missing weak-linked target class", cat->name, cat); } continue; } // 首先,通过其所属的类注册Category。如果这个类已经被实现,则重新构造类的方法列表。 bool classExists = NO; if (cat->instanceMethods || cat->protocols || cat->instanceProperties) { // 将Category添加到对应Class的value中,value是Class对应的所有category数组 addUnattachedCategoryForClass(cat, cls, hi); // 将Category的method、protocol、property添加到Class // 判断 cls 是否实现 if (cls->isRealized()) { remethodizeClass(cls); classExists = YES; } if (PrintConnecting) { _objc_inform("CLASS: found category -%s(%s) %s", cls->nameForLogging(), cat->name, classExists ? "on existing class" : ""); } } // 这块和上面逻辑一样,区别在于这块是对Meta Class做操作,而上面则是对Class做操作 // 根据下面的逻辑,从代码的角度来说,是可以对元类添加Category的 if (cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) { addUnattachedCategoryForClass(cat, cls->ISA(), hi); if (cls->ISA()->isRealized()) { remethodizeClass(cls->ISA()); } if (PrintConnecting) { _objc_inform("CLASS: found category +%s(%s)", cls->nameForLogging(), cat->name); } } } // 初始化从磁盘中加载的所有类,发现Category必须是最后执行的 // 从runtime DebugNonFragileIvars字段一直是 false,所以不会进入这个方法中 if (DebugNonFragileIvars) { realizeAllClasses(); } //... 忽略一些打印的代码 } 复制代码
在 read_images
里经常出现 _getObjc2ClassRefs
之类的代码,这是从 Mach-O
文件里面读取相应 setion
段的数据,我们通过 MachOView
可以看到相关 setion
段的信息。
load_images
函数是对 load
方法的加载和调用,接下来我们就来看看底层是怎么对 load
处理的。
void load_images(const char *path __unused, const struct mach_header *mh) { // 如果这里没有+load方法,则返回时不带锁。 if (!hasLoadMethods((const headerType *)mh)) return; recursive_mutex_locker_t lock(loadMethodLock); { mutex_locker_t lock2(runtimeLock); // 准备 load 方法 prepare_load_methods((const headerType *)mh); } // 调用 load 方法 call_load_methods(); } 复制代码
进到 prepare_load_methods
可以看到系统是如何加载 load
方法的。
void prepare_load_methods(const headerType *mhdr) { size_t count, i; runtimeLock.assertLocked(); // 获取非懒加载类列表 classref_t *classlist = _getObjc2NonlazyClassList(mhdr, &count); for (i = 0; i < count; i++) { // 循环遍历去加载非懒加载类的 load 方法到 loadable_classes 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 if (cls->isSwiftStable()) { _objc_fatal("Swift class extensions and categories on Swift " "classes are not allowed to have +load methods"); } // 如果本类没有初始化就去初始化 realizeClassWithoutSwift(cls); assert(cls->ISA()->isRealized()); // 循环遍历去加载非懒加载分类的 load 方法到 loadable_categories // 和非懒加载类差不多,就是数组不一样 add_category_to_loadable_list(cat); } } static void schedule_class_load(Class cls) { if (!cls) return; assert(cls->isRealized()); // _read_images should realize if (cls->data()->flags & RW_LOADED) return; // 常规操作,递归调用父类加载 load 方法 schedule_class_load(cls->superclass); // 将 load 方法加载到 loadable_classes add_class_to_loadable_list(cls); cls->setInfo(RW_LOADED); } void add_class_to_loadable_list(Class cls) { IMP method; loadMethodLock.assertLocked(); // 获取 load 方法的 imp method = cls->getLoadMethod(); // 如果没有 load 方法直接返回 if (!method) return; 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 添加 load 方法 loadable_classes[loadable_classes_used].cls = cls; loadable_classes[loadable_classes_used].method = method; loadable_classes_used++; } 复制代码
从上面准备 load
方法的代码,可以看出,是先去加载父类的,然后再加载本类,之后再去加载分类的 load
方法。我们再看看是怎么调用 load
方法的。
void call_load_methods(void) { static bool loading = NO; bool more_categories; loadMethodLock.assertLocked(); // 保证只调用一次 if (loading) return; loading = YES; void *pool = objc_autoreleasePoolPush(); // do while 循环调用 load 方法 do { // 1.重复调用非懒加载类的 load,直到没有更多的 while (loadable_classes_used > 0) { call_class_loads(); } // 2.调用非懒加载分类的 load 方法,和非懒加载类差不多 more_categories = call_category_loads(); // 3. 如果有类或更多未尝试的类别,则运行更多 load } while (loadable_classes_used > 0 || more_categories); objc_autoreleasePoolPop(pool); loading = NO; } static void call_class_loads(void) { int i; // 取出 loadable_classes struct loadable_class *classes = loadable_classes; int used = loadable_classes_used; loadable_classes = nil; loadable_classes_allocated = 0; loadable_classes_used = 0; // 调用保存在 loadable_classes 里的 load 方法 for (i = 0; i < used; i++) { Class cls = classes[i].cls; 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); } // 释放内存 if (classes) free(classes); } 复制代码
load
的调用,可以得出,load
的调用顺序是:父类->本类->分类。unmap_image
是用来处理将被 dyld
取消映射的给定 images
。
void unmap_image(const char *path __unused, const struct mach_header *mh) { recursive_mutex_locker_t lock(loadMethodLock); mutex_locker_t lock2(runtimeLock); unmap_image_nolock(mh); } void unmap_image_nolock(const struct mach_header *mh) { if (PrintImages) { _objc_inform("IMAGES: processing 1 newly-unmapped image...\n"); } header_info *hi; // 查找映像的运行时 header_info 结构 for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) { if (hi->mhdr() == (const headerType *)mh) { break; } } if (!hi) return; if (PrintImages) { _objc_inform("IMAGES: unloading image for %s%s%s\n", hi->fname(), hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "", hi->info()->isReplacement() ? " (replacement)" : ""); } // 目前只处理 MH_BUNDLE _unload_image(hi); // 从标题列表中删除 header_info removeHeader(hi); free(hi); } 复制代码
_objc_init
函数,执行 _dyld_objc_notify_register
,再通过 dyld
的 registerObjCNotifiers
回调到 _dyld_objc_notify_register
并执行 map_images
、load_images
、unmap_image
。map_images
加载镜像文件,_read_images
读取镜像文件并加载类。_read_images
的时候会去初始化两张表 gdb_objc_realized_classes
和 allocatedClasses
进行类信息的存储。readClass
是将类插入到 allocatedClasses
表中的。remapClassRef
进行修复类的重映射和 fixupMessageRef
修复旧的函数指针调用遗留。realizeClassWithoutSwift
去初始化类,其中是对类的 rw
实例化,以及将 ro
数据赋值到 rw
上。load_images
是对 load
方法的处理以及调用,调用顺序是 父类->本类->分类,而有多个分类 load
的时候是根据编译顺序执行的。unmap_image
是用来处理将被 dyld 取消映射的给定 images。