美文网首页
Extension和Category本质区别

Extension和Category本质区别

作者: iOS劝退师 | 来源:发表于2021-04-23 17:56 被阅读0次

    Category是运行时决议生效的,Extension是编译时就决议生效的
    Category不可以添加实例变量,Extension可以。
    Extension和category都可以添加属性,但是Category的属性不能生成成员变量和getter、setter方法的实现
    Category是有声明和实现,Extension是直接写在宿主类的.m文件中,只有声明

    Category

    先看看Category 的结构体

    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);   ///获取实例属性列表和类属性列表。
    };
    

    从category结构体可以看出来,category可以添加实例方法,类方法,甚至可以实现协议,添加属性
    小贴士:类属性类和实例都可以访问,实例属性类不可以访问只有类能访问

    所以category是允许添加属性的,同样可以使用@property,但是不能生成成员变量,也不能生成添加属性的getter和setter方法的实现,所以尽管添加了属性,也无法使用点语法调用getter和setter方法。但是可以使用runtime去实现category为已有的类添加新的属性并生产getter和setter方法。

    那为什么Category的属性不能为类添加成员变量,原因要看runtime中class的结构体.
    如下,类结构体中的 objc_ivar_list 实例变量的链表和 instance_size 实例变量的内存大小在编译时已经确定,而Category又是运行时,因此无法向已经编译完成的类中增加实例变量。

    typedef struct objc_class *Class;
    
    struct objc_class {
        //结构体的第一个成员变量也是isa指针,这就说明了Class本身其实也是一个对象,因此我们称之为类对象,类对象在编译期产生用于创建实例对象,是单例。
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    
    #if !__OBJC2__
        Class _Nullable super_class                              OBJC2_UNAVAILABLE;
        const char * _Nonnull name                               OBJC2_UNAVAILABLE;
        long version                                             OBJC2_UNAVAILABLE;
        long info                                                OBJC2_UNAVAILABLE;
        long instance_size                                       OBJC2_UNAVAILABLE;
        struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
        struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
        struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
        struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
    #endif
    
    } OBJC2_UNAVAILABLE;
    

    Extension

    那为什么Extension可以添加呢。其实上面已经说明了答案,Extension是编译时,因此可以在类的结构体编译完成前将成员变量加上

    相关文章

      网友评论

          本文标题:Extension和Category本质区别

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