美文网首页
load方法探索

load方法探索

作者: Code_人生 | 来源:发表于2019-09-29 16:14 被阅读0次

    一、调用规则

    • 1、一个类的load方法在所有父类load方法调用之后调用
    • 2、分类的load方法在当前类的load方法调用之后调用
    • 3、分类load的调用顺序和编译顺序有关(这个就不需要考虑分类对应的类的父子关系了)

    总结:
    1、先调用所有类的load方法,调用顺序和编译顺序有关,如果有父类先调用父类的,再调用自己(这时如果父类的编译顺序再后面,也会先调用父类的,再调用自己的)(如果父类在前面那就直接调用了哈)
    2、再调用分类的load方法,调用顺序和编译顺序有关(这个就不需要考虑分类对应的类的父子关系了)

    二、load方法的调用

    • objc4-750源码中搜索_objc_init
    • _dyld_objc_notify_register(&map_images, load_images, unmap_image);
      • &map_images dyld将image加载进内存
      • load_images dyld初始化image,load方法也在此调用
      • unmap_image 移除内存
    // objc-os.mm
    void _objc_init(void)
    {
        static bool initialized = false;
        if (initialized) return;
        initialized = true;
        
        // fixme defer initialization until an objc-using image is found?
        environ_init();
        tls_init();
        static_init();
        lock_init();
        exception_init();
    
        _dyld_objc_notify_register(&map_images, load_images, unmap_image);
    }
    
    • 步骤1、点击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();
    }
    
    • 步骤2、点击prepare_load_methods
    void prepare_load_methods(const headerType *mhdr)
    {
        size_t count, i;
    
        runtimeLock.assertLocked();
    
        //从 Macho 文件加载类的列表
        classref_t *classlist = 
            _getObjc2NonlazyClassList(mhdr, &count);
        for (i = 0; i < count; i++) {
            //数组:[<cls,method>,<cls,method>,<cls,method>] 有顺序
            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
            realizeClass(cls);
            assert(cls->ISA()->isRealized());
            add_category_to_loadable_list(cat);
        }
    }
    
    • 步骤2.1、点击schedule_class_load
    //递归调用
    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); 
    }
    
    • 点击add_class_to_loadable_list
    void add_class_to_loadable_list(Class cls)
    {
        IMP method;
    
        loadMethodLock.assertLocked();
    
        method = cls->getLoadMethod();
        if (!method) return;  // Don't bother if cls has no +load method
        
        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[loadable_classes_used].cls = cls;
        loadable_classes[loadable_classes_used].method = method;
        loadable_classes_used++;
    }
    
    • 步骤2.2、点击add_category_to_loadable_list
    void add_category_to_loadable_list(Category cat)
    {
        IMP method;
    
        loadMethodLock.assertLocked();
    
        method = _category_getLoadMethod(cat);
    
        // Don't bother if cat has no +load method
        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++;
    }
    
    • 步骤3、点击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) {
                //先调用类的 load 方法
                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;
    }
    
    • 总结
      • 1、load_images
      • 2、prepare_load_methods
        • 2.1、调整当前的调用顺序
        • 2.2、类,递归遍历,loadable_classes<cls,method>
        • 2.3、分类,loadable_category,编译顺序有关的!
      • 3、call_load_methods()
        • 3.1、先调用loadable_classes
        • 3.2、后调用loadable_category

    相关文章

      网友评论

          本文标题:load方法探索

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