美文网首页
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