runtime加载过程

633 阅读6分钟

iOS程序加载过程

  1. 在程序启动之后,由dyld(动态链接编辑器)将程序加载到二进制中,完成一些文件的初始化操作。
  2. Runtime向dyld中注册回调函数。
  3. 通过ImageLoader将所有的image加载到内存中。
  4. dyld在images发生改变时主动调用回调函数。
  5. Runtime在接收到回调函数后开始执行map_images,load_images等函数,并回调+load函数。
  6. 调用main()函数,开始执行业务代码。

map_images

在Runtime加载过程中,会调用_objc_init函数,在_objc_init函数中主要调用了map_images,load_images等方法

void _objc_init(void) {
// .... 各种init
     _dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
//主要作用是一个调用中转
 void map_images(unsigned count, const char * const paths[], const struct mach_header * const mhdrs[])
{
    rwlock_writer_t lock(runtimeLock);
    return map_images_nolock(count, paths, mhdrs);
}

void map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
    if (hCount > 0) {
         _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
      }
}

read_images主要逻辑:

  1. 加载所有类到gbd_objc_readlized_classes表中
  2. 对所有类做重映射
  3. 将所有SEL都注册到namedSelectors表中
  4. 修复函数指针遗留
  5. 将所有的Protocol都添加到protocol_map表中
  6. 多所有的Protocol做重映射
  7. 初始化所有非懒加载的类,进行rw,ro操作
  8. 遍历已标记的懒加载的类,并做初始化操作
  9. 处理所有Category,包括Class和Meta Class
  10. 初始化所有未初始化的类
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unopt imizedTotalClasses)
{
    header_info *hi;
    uint32_t hIndex;
    size_t count;
    size_t i;
    Class *resolvedFutureClasses = nil;
    size_t resolvedFutureClassCount = 0; 
    static bool doneOnce;
    TimeLogger ts(PrintImageTimes);
#define EACH_HEADER \
    hIndex = 0;         \
    hIndex < hCount && (hi = hList[hIndex]); \
    hIndex++
    if (!doneOnce) { 
         doneOnce = YES;
         //实例化存储类的哈希表,并根据当前类数量做动态扩容
         int namedClassesSize = (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
         gdb_objc_realized_classes = NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
     }
//由编辑器读取类列表,并将所有的类添加到哈希表中,并标记懒加载的类并初始化空间
    for (EACH_HEADER) {
         if (! mustReadClasses(hi)) { 
            continue;
         }
         bool headerIsBundle = hi->isBundle();
         bool headerIsPreoptimized = hi->isPreoptimized();
         /** 将新类添加到哈希表中 */
         // 从编译后的类列表中取出所有类,获取到一个classref_t类型指针
         classref_t *classlist = _getObjc2ClassList(hi, &count);
         for (i = 0; i < count; i++) {
             // 数组中取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunLoop等系统类<CF、Fundation、liddispatch等>和自己创建的类
             Class cls = (Class)classlist[i];
             // 通过readClass函数获取处理过后的新类,内部主要操作ro和rw结构体
             Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
             // 初始化所有懒加载的类需要的内存空间
             if (newCls != cls && newCls) {
                 // 将懒加载的类添加到数组中 
                 resolvedFutureClasses = (Class *)realloc(resolvedFutureClasses, (resolvedFutureClassCount+1) * sizeof(Class));
                 resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
             }
         }
     }

//将为映射的Class和superClass重映射,被remap的类都是非懒加载的类
     if (!noClassesRemapped()) {
         for (EACH_HEADER) {
         // 重映射Class,从_getObjc2ClassRefs函数中取出类的引用
             Class *classrefs = _getObjc2ClassRefs(hi, &count);
             for (i = 0; i < count; i++) {
                 remapClassRef(&classrefs[i]);
             }
         } 
         // 重映射父类
         classrefs = _getObjc2SuperRefs(hi, &count); 
         for (i = 0; i < count; i++) {
             remapClassRef(&classrefs[i]);
         }
     }

     // 对SEL做重映射
     static size_t UnfixedSelectors; sel_lock();
     for (EACH_HEADER) {
         if (hi->isPreoptimized()) continue;
         bool isBundle = hi->isBundle();
         SEL *sels = _getObjc2SelectorRefs(hi, &count); UnfixedSelectors += count;
         for (i = 0; i < count; i++) {
             const char *name = sel_cname(sels[i]);
             //注册SEL
             sels[i] = sel_registerNameNoLock(name, isBundle);
         } 
     }
     // 修复旧的函数指针遗留
     for (EACH_HEADER) {
         message_ref_t *refs = _getObjc2MessageRefs(hi, &count); 
         if (count == 0) continue;
         for (i = 0; i < count; i++) {
             // 在内部将常用的alloc、objc_msgSend等函数指针进行注册,并fix为新的函数指针
             fixupMessageRef(refs+i);
         }
     }
     // 遍历所有协议列表,并且将协议列表加载到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);
         }
     }
     // 修复协议列表应用,优化后的images不确定正确与否
     for (EACH_HEADER) {
         //下面的_getObjc2ProtocolRefs函数与上面的_getObjc2ProtocolRefs不同
         protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
         for (i = 0; i < count; i++) {
            remapProtocolRef(&protolist[i]);
         }
     }
     
     // 实现非懒加载的类
     for (EACH_HEADER) {
         classref_t *classlist =
            _getObjc2NonlazyClassList(hi, &count);
         for (i = 0; i < count; i++) {
             Class cls = remapClass(classlist[i]);
             if (!cls) continue;
             //实现非来加载的类(实例化一些信息,如rw)
             realizeClass(cls);
         }    
     }
     
     // 遍历resolvedFutureClasses数组,实现所有懒加载的类
     if (resolvedFutureClasses) {
         for (i = 0; i < resolvedFutureClassCount; i++) {
             // 实现懒加载的类
             realizeClass(resolvedFutureClasses[i]); resolvedFutureClasses[i]->setInstancesRequireRawIsa(false/*inherited*/);
         }
        free(resolvedFutureClasses);
     }
     
// 发现和处理所有Category
     for (EACH_HEADER) {
         // 外部循环遍历找到当前类,查找类对应的Category数组
         category_t **catlist = _getObjc2CategoryList(hi, &count);
         bool hasClassProperties = hi->info()->hasCategoryClassProperties();

         内部循环遍历当前类的所有的Category 
         for (i = 0; i < count; i++) {
             category_t *cat = catlist[i];
             Class cls = remapClass(cat->cls);
             // 首先,通过所属的类注册Category。如果这个类已经被实现,则重新构造类的方法列表 
             bool classExists = NO;
             if (cat->instanceMethods || cat->protocols || cat->instanceProperties) {
                 // 将Category添加到对应的value中,value是Class对应的所有的Category数组
                 addUnattachedCategoryForClass(cat, cls, hi);
                 // 将Category的method,protocol,property添加到Class中
                 if (cls->isRealized()) {
                     remethodizeClass(cls);
                     classExists = YES;
                 }
             }
             // 与下面逻辑相同,不过是在Meta Class中进行操作
             if (cat->classMethods || cat->protocols || (hasClassProperties && cat->_classProperties)) {
                 addUnattachedCategoryForClass(cat, cls->ISA(), hi); 
                 if (cls->ISA()->isRealized()) {
                     remethodizeClass(cls->ISA());
                 }

             }
         }
     }
     
     // 初始化所有的类,Category必须是最后执行
     // DebugNonFragileIvars = -1,不执行
     if (DebugNonFragileIvars) {
         realizeAllClasses();
     }
#undef EACH_HEADER
}

load_images


     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);
                 //主要查找Class、Category的方法方法
                 prepare_load_methods((const headerType *)mh);
             }
             // Call +load methods (without runtimeLock - re-entrant)
             // 调用Class、Category的方法列表
              call_load_methods();
     }
     
     
     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++) {
             // 设置Class的调用列表
             schedule_class_load(remapClass(classlist[i]));
         }
         // 获取Category的列表
         category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
         for (i = 0; i < count; i++) {
             category_t *cat = categorylist[i];
             Class cls = remapClass(cat->cls);
             // category for ignored weak-linked class,忽略弱链接<不懂>的类别
             if (!cls) continue;  
             // 实例化所属的类
             realizeClass(cls);
             assert(cls->ISA()->isRealized());
             // 设置Categoty的调用列表
             add_category_to_loadable_list(cat);
         }
     }
     static void schedule_class_load(Class cls) {
         
         if (!cls) return;
         // _read_images should realize,_read_images是否完成
         assert(cls->isRealized());  
         // 已经添加完成,则return
         if (cls->data()->flags & RW_LOADED) return;

         // Ensure superclass-first ordering,确保superClass添加
         schedule_class_load(cls->superclass);
         // 添加imp、class到调用中
         add_class_to_loadable_list(cls);  
         // 设置class的标识符,表示已添加到list中
         cls->setInfo(RW_LOADED); 
     }
    
     // 在obj-loadmethod.mm中
     void add_category_to_loadable_list(Category cat) {
         IMP method;
         // 获取Category中Load方法的imp
         loadMethodLock.assertLocked();
         method = _category_getLoadMethod(cat);
         // Don't bother if cat has no +load method,没有则return
         if (!method) return;

         if (PrintLoading) {
             _objc_inform("LOAD: category '%s(%s)' scheduled for +load", 
                     _category_getClassName(cat), _category_getName(cat));
         }
             如果已使用大小等于数组大小,对数组进行动态扩容
         if (loadable_categories_used == loadable_categories_allocated) {
             loadable_categories_allocated = loadable_categories_allocated*2 + 16;
             loadable_categories = (struct loadable_category *)
             realloc(loadable_categories,loadable_categories_allocated * sizeof(struct loadable_category));
         }

         loadable_categories[loadable_categories_used].cat = cat;
         loadable_categories[loadable_categories_used].method = method;
         loadable_categories_used++;
     }
     
     // 准备好了loadable_calss、loadable_categories数组,load_images会通过call_load_methods函数执行这些load方法
     
     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;
     }
     
     // 通过遍历获得loadable_class结构体
     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_method_t load_method = (load_method_t)classes[i].method;
             if (!cls) continue; 

             if (PrintLoading) {
                 _objc_inform("LOAD: +[%s load]\n", cls->nameForLogging());
             }
             (*load_method)(cls, SEL_load);
         }
    // Destroy the detached list.
         if (classes) free(classes);
     }
     
     
     struct loadable_class {
         Class cls; // may be nil 
         IMP method;
     };
    
  1. 通过上述代码,发现load方法的调用顺序为 父类 -> 子类 -> Category。
  2. category的 load方法会覆盖 class的 load方法