美文网首页
iOS 类的加载之load_images

iOS 类的加载之load_images

作者: 瞬间完善 | 来源:发表于2020-01-28 14:55 被阅读0次

    类的加载中我们知道了加载类时候会调用_objc_init函数,然后执行_dyld_objc_notify_register函数,并传入了map_imagesload_images参数,我们在类的加载中分析了map_images,今天我们来看一下load_images
    我们知道非懒加载类会实现load方法,那么在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);
            prepare_load_methods((const headerType *)mh);
        }
    
        // Call +load methods (without runtimeLock - re-entrant)
        call_load_methods();
    }
    

    从这里我们可以直接锁定终点代码12行prepare_load_methods和16行call_load_methods代码,这两个地方才是进行具体的操作的,我们首先看一下prepare_load_methods是做什么的?

    void prepare_load_methods(const headerType *mhdr)
    {
        size_t count, i;
    
        runtimeLock.assertLocked();
    // ✅ 获取非懒加载类的列表,并调用schedule_class_load添加类到add_class_to_loadable_list表中
        classref_t *classlist = 
            _getObjc2NonlazyClassList(mhdr, &count);
        for (i = 0; i < count; i++) {
            schedule_class_load(remapClass(classlist[i]));
        }
    // ✅ 获取取非懒加载categorylist,如果存在,则进行realizeClassWithoutSwift,然后添加分类到add_category_to_loadable_list
        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());
            add_category_to_loadable_list(cat);
        }
    }
    

    我们在看一下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;
    }
    

    通过以上代码我们可以看到,call_load_methods函数是通过一个do...while循环进行classload方法调用和分类categoryload方法调用。

    总结

    • load_images是通过prepare_load_methodscall_load_methods进行实现
    • prepare_load_methods是对load方法调用进行准备工作
      • 调用schedule_class_load添加类到add_class_to_loadable_list表中
      • 添加分类到add_category_to_loadable_list表中
    • 然后执行call_load_methods,通过一个do...while循环进行类classload方法调用和分类categoryload方法调用。

    面试题

    classcategory都实现了load方法,会怎么调用?普通方法又怎么调用?

    • 在处理load方法调用的时候先进行了call_class_loads,也就是类classload方法调用,在通过call_category_loads处理分类categoryload方法调用。
    • 类的加载中我们对map_images分析到,category是通过attachrwmethodList。而attach的过程是将新的list添加到栈的头部,所以调用方法的时候从头部开始查找,自然会先找到category中的方法然后进行调用。这就会造成category的中的方法会覆盖class中方法的假像

    相关文章

      网友评论

          本文标题:iOS 类的加载之load_images

          本文链接:https://www.haomeiwen.com/subject/xknpthtx.html