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 isaOBJC_ISA_AVAILABILITY; #if !__OBJC2__ Class _Nullable super_classOBJC2_UNAVAILABLE; const char * _Nonnull nameOBJC2_UNAVAILABLE; long versionOBJC2_UNAVAILABLE; long infoOBJC2_UNAVAILABLE; long instance_sizeOBJC2_UNAVAILABLE; struct objc_ivar_list * _Nullable ivarsOBJC2_UNAVAILABLE; struct objc_method_list * _Nullable * _Nullable methodListsOBJC2_UNAVAILABLE; struct objc_cache * _Nonnull cacheOBJC2_UNAVAILABLE; struct objc_protocol_list * _Nullable protocolsOBJC2_UNAVAILABLE; #endif} OBJC2_UNAVAILABLE;

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

    推荐阅读