Category

作者: 越天高 | 来源:发表于2020-10-21 15:57 被阅读0次

    01-基本使用

    Category的使用场合是什么?
    为现有的类添加的新的方法,又不想改原来的类的时候

    Category的实现原理
    Category编译之后的底层结构是struct category_t,里面存储着分类的对象方法、类方法、属性、协议信息
    在程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)

    Category和Class Extension的区别是什么?
    Class Extension在编译的时候,它的数据就已经包含在类信息中
    Category是在运行时,才会将数据合并到类信息中

    我们平时方法的调用就是发消息,他会根据isa根据找到类对象,去找方法,一个类只存在一个类对象,他的分类的方法存在于类对象之中,合并一起,如果是调的用是分类中类方法,他会的类方法存在于元类对象之中。

    Category的地层结构

    分类的合并并不是编译的时候,是在程序的运行的时候合并的,我们可以转成C++代码来查看,他首先会把分类的中的方法放到一个结构体里面,运行的时候才把他合并到类对象里面。
    编译的时候 每一个分类都是在内存中转成下面这种结构体

    struct category_t {
        const char *name;
        classref_t cls;
        struct method_list_t *instanceMethods;
        struct method_list_t *classMethods;
        struct protocol_list_t *protocols;
        struct property_list_t *instanceProperties;
        // Fields below this point are not always present on disk.
        struct property_list_t *_classProperties;
    
        method_list_t *methodsForMeta(bool isMeta) {
            if (isMeta) return classMethods;
            else return instanceMethods;
        }
    
        property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
        
        protocol_list_t *protocolsForMeta(bool isMeta) {
            if (isMeta) return nullptr;
            else return protocols;
        }
    };
    

    03源码分析

    运行时,他会将每一个分类的对象想法 合并到类对象中,将类方法合并到元类对象之中。
    查看远嘛文件

    objc-os.mm//运行的入口
    objc_init//运行时的初始化
    map_images //
    map_images_nolock
    objc_runtime_new.mm
     _read_images//镜像。模块.,他会读取所有的类信息,这里面会有一个Discover categories
    重新组织方法,将分类的方法加到了原来的数组列表里面 
       remethodizeClass
        attachCategories
        attachLists 将所有分类方法附加到,类对象的方法列表中
        realloc、memmove、 memcpy
    
    

    1通过Runtime加载某个类的所有Category数据

    2把所有Category的方法、属性、协议数据,合并到一个大数组中
    后面参与编译的Category数据,会在数组的前面

    3将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面

    04源码分析02

    attachLists内部做的事情,他会从新分布内存,旧的内存加上新的内存

    void attachLists(List* const * addedLists, uint32_t addedCount) {
            if (addedCount == 0) return;
    
            if (hasArray()) {
                // many lists -> many lists
    //array()原来的方法列表
                uint32_t oldCount = array()->count;
                uint32_t newCount = oldCount + addedCount;
                setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
                array()->count = newCount;
                memmove(array()->lists + addedCount, array()->lists, 
                        oldCount * sizeof(array()->lists[0]));
    //addedLists 所有分类的方法列表
                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;
                if (oldList) array()->lists[addedCount] = oldList;
                memcpy(array()->lists, addedLists, 
                       addedCount * sizeof(array()->lists[0]));
            }
        }
    

    他会将原来的方法列表里面的数据,往后移动,然后将分类的方法列表数据添加到原来方法列表所在的地方。所以同样的方法,他会优先调用分类的方法,因为数组要进行两次,先添加到addlist里面,在添加到原来的方法类表里,所以最后编译的分类放到了,合并之后的方法列表的最前面。
    分类的方法覆盖并不是真的覆盖,他只是放在了原来类对象的方法前面

    Category和Class Extension的区别是什么?
    @interface SLPerson()
    @end
    Class Extension在编译的时候,它的数据就已经包含在类信息中
    Category是在运行时,才会将数据合并到类信息中
    这里面的东西,编译的时候就合并到了类对象里面。分类是运行时在添加类对象里面

    05-memmove、memcpy区别

    memcpy 如果我们使用memcpy把两个数据往后移动一下,3 4 51,
    他会先移动第一个3-> 3 3 5 1,然后在去移动第二位的数据-> 3 3 3 1。这样并不能达到我们想要的效果,
    如果我们想要使用memmove他会根据内存的地址大小,来判断挪动的方向-> 3 3 4 5 。他可以保证原来的数据的完整性

    06答疑

    在类对象的结构体里面的class_rw_t里面有个ro表,它里面存在着类原来的数据包括baseMethodList,这里面就不包括分类的方法列表

    相关文章

      网友评论

        本文标题:Category

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