美文网首页
分类中添加方法的实现原理

分类中添加方法的实现原理

作者: 初灬终 | 来源:发表于2019-10-12 22:33 被阅读0次

    方法调用

    image.png

    源码(主干部分)

    static void 
    attachCategories(Class cls, category_list *cats, bool flush_caches)
    {
        bool isMeta = cls->isMetaClass();
        method_list_t **mlists = (method_list_t **) malloc(cats->count * sizeof(*mlists));
    
        int mcount = 0;
        int i = cats->count;
        bool fromBundle = NO;
    
        //反向遍历,将分类的方法添加到mlist数组。
        while (i--) {
            auto& entry = cats->list[i];
    
            method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
            if (mlist) {
                mlists[mcount++] = mlist;
            }
        }
        //获取class的相关信息,其中包含方法列表
        auto rw = cls->data();
        
        //在class的方法列表上,拼接上分类的方法列表
        //调用该方法后,分类方法才真正添加到class的方法列表中。
        rw->methods.attachLists(mlists, mcount);
    }
    
    void attachLists(List* const * addedLists, uint32_t addedCount) {
        if (addedCount == 0) return;
    
        if (hasArray()) {
            // many lists -> many lists
            //原有方法数量
            uint32_t oldCount = array()->count;
            //新增方法数量
            uint32_t newCount = oldCount + addedCount;
            //分配方法的内存空间
            setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
            array()->count = newCount;
            
            //内存移动。将类的原有方法,移动到分类方法之后。
            //array()->lists,迭代器里的List **lists,表示未拼接分类方法的二维数组。
            //addedCount是一个uint32_t(4Byte),array()->lists是指针(4Byte)的数组
            //sizeof(array()->lists[0])  = sizeof(指针)
            memmove(array()->lists + addedCount, array()->lists, 
                    oldCount * sizeof(array()->lists[0]));
            
            //内存复制。将新增的分类方法,拷贝到类的方法列表中,从首地址开始。
            memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));
        }
        else if (!list  &&  addedCount == 1) {
            // 0 lists -> 1 list
            list = addedLists[0];
        } 
        else {
            // 1 list -> many lists
            List* oldList = list;
            uint32_t oldCount = oldList ? 1 : 0;
            uint32_t newCount = oldCount + addedCount;
            setArray((array_t *)malloc(array_t::byteSize(newCount)));
            array()->count = newCount;
            //将class的原有方法,移动到分类方法之后。
            if (oldList) array()->lists[addedCount] = oldList;
            memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));
        }
    }
    

    总结

    0.分类的方法,是在编译的时候添加的,还是运行时添加?

    运行时

    1.为什么分类方法会覆盖掉原有方法?
    memmove(array()->lists + addedCount, array()->lists, 
                    oldCount * sizeof(array()->lists[0]));
    memcpy(array()->lists, addedLists, 
                   addedCount * sizeof(array()->lists[0]));
    

    因为分类的方法,在方法列表中的位置,在原有方法之前。实际上原有方法依旧存在,没有被真正的覆盖。

    2.为什么分类中的同名方法,最后编译的分类生效?

    因为分类方法是反向遍历的,最后编译的方法,它在方法列表中的位置越靠前。实际上所有的同名方法都存在。

    相关文章

      网友评论

          本文标题:分类中添加方法的实现原理

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