美文网首页
底层原理总结 — Category3

底层原理总结 — Category3

作者: 踩坑小分队 | 来源:发表于2020-02-25 22:53 被阅读0次
    问题

    Person类中有一个run方法,
    PersonCategory1中也有一个run方法,
    PersonCategory2中也有一个run方法,
    调用[Person run]时响应的是哪个方法?

    答案:

    根据两个分类的编译顺序,调用的是后编译的Category中的run方法。

    编译顺序.png
    原因:

    runtimePerson的元类对象中的类方法和Category中的类方法合并了,逆序<编译顺序>获取分类指针,并且将Category中的类方法,放在了方法列表的前面。所以调用run方法的时候,优先找到的是Category中的类方法。

    方法列表顺序为:

    【Category2】【Category1】【Person】


    接着上面的问题继续:

    Person中实现+(void)load方法,
    PersonCategory1中实现+(void)load方法,
    PersonCategory2中实现+(void)load方法
    运行,调用谁的load方法?

    答案:

    都调用了

    load -- Person
    load -- Person (Extension1)
    load -- Person (Extension2)
    

    感觉和上面的问题对不上了。方法名一样的话不应该只调用一个吗?

    原因分析:

    下载objc源码看一下
    源码地址:https://opensource.apple.com/tarballs/objc4/
    顺着下面的方法直接找到最终目的地
    void _objc_init(void)
    load_images
    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;
    }
    
    第一步,调用所有的类的load方法
     // 1. Repeatedly call class +loads until there aren't any more
            while (loadable_classes_used > 0) {
                call_class_loads();
            }
    

    call_class_loads();中,
    循环遍历所有的class
    然后直接找到load方法,
    直接进行调用<(*load_method)(cls, SEL_load);>

    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);
        }
    
    第二步,调用所有分类中的load方法

    call_category_loads();

    for (i = 0; i < used; i++) {
            Category cat = cats[i].cat;
            load_method_t load_method = (load_method_t)cats[i].method;
            Class cls;
            if (!cat) continue;
    
            cls = _category_getClass(cat);
            if (cls  &&  cls->isLoadable()) {
                if (PrintLoading) {
                    _objc_inform("LOAD: +[%s(%s) load]\n", 
                                 cls->nameForLogging(), 
                                 _category_getName(cat));
                }
                (*load_method)(cls, SEL_load);
                cats[i].cat = nil;
            }
        }
    

    所以+ (void)load;方法class中和Category中的都会在runtime的时候调用

    原因

    调用顺序
    先调用class中的load方法
    再按照编译顺序调用Category中的load方法

    相关文章

      网友评论

          本文标题:底层原理总结 — Category3

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