iOS 类的加载之load_images

2020-01-28  本文已影响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方法调用。

总结

面试题

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

上一篇下一篇

猜你喜欢

热点阅读