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

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

作者: 初灬终 | 来源:发表于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.为什么分类中的同名方法,最后编译的分类生效?

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

相关文章

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

    方法调用 源码(主干部分) 总结 0.分类的方法,是在编译的时候添加的,还是运行时添加? 运行时 1.为什么分类方...

  • iOS开发 Category

    1.说下category原理,以及category为什么只能添加方法不能添加属性? 分类的实现是将category...

  • iOS Category分类

    1.说下category原理,以及category为什么只能添加方法不能添加属性? 分类的实现是将category...

  • iOS-OC基础知识点扩展

    请简述分类实现原理 KVO的实现原理是怎样的 能否为分类添加成员变量 目录 分类 & 关联对象 & 扩展 & 代理...

  • KVO底层实现原理

    添加观察者方法实现原理 监听方法自动调用实现原理

  • 动态添加属性

    动态向类中加入属性 (未实现的方法并没有在类的MethodList)在分类中只能添加方法,不能添加属性,在分类中声...

  • 分类中添加属性的实现原理

    相关Class或Struct AssociationsManager:全局唯一的关联对象管理者。 Associat...

  • iOS 面试全方位剖析 -- OC语言特性篇

    通过这篇文章要了解的面试问题 请简述分类实现原理 KVO的实现原理是怎样的 能否为分类添加成员变量 目录 分类 &...

  • OC中分类的实现原理

    OC中为类添加一个分类(Category)可以实现为类添加对象方法、类方法、添加属性(添加的属性不生成成员变量)、...

  • 04-Category(分类)/Extension(匿名分类/类

    一、Category 1、Category的基本使用 2、Category的实现原理 分类中的对象方法、类方法、协...

网友评论

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

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