Extension和Category本质区别

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本质区别)