Category的底层原理
2019-04-13 本文已影响0人
春风依旧
category是Objective-C 2.0之后添加的语言特性,为本类扩展私有方法,
分类的基础知识可以看这篇category基础知识篇
1、category中能添加属性吗?
struct _category_t {
const char *name; //类名
struct _class_t *cls; /类
const struct _method_list_t *instance_methods; //实例方法列表
const struct _method_list_t *class_methods; //类方法列表
const struct _protocol_list_t *protocols; //协议列表
const struct _prop_list_t *properties; //属性列表
};
category中也可以添加属性,只不过@property只会生成setter和getter的声明,不会生成setter和getter的实现以及成员变量,点语法是可以写,只不过在运行时调用到这个方法时候会报方法找不到的错误。
2、为什么category不能添加成员变量
Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。它的定义如下:
typedef struct objc_class *Class;
objc_class结构体的定义如下:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class // 父类
const char *name // 类名
long version // 类的版本信息,默认为0
long info // 类信息,供运行期使用的一些位标识
long instance_size // 该类的实例变量大小
struct objc_ivar_list *ivars // 该类的成员变量链表
struct objc_method_list **methodLists // 方法定义的链表
struct objc_cache *cache // 方法缓存
struct objc_protocol_list *protocols // 协议链表
#endif
};
objc_method_list指针的指针。在Runtime中,objc_class结构体大小是固定的,不可能往这个结构体中添加数据,只能修改。所以ivars指向的是一个固定区域,只能修改成员变量值,不能增加成员变量个数。methodList是一个二维数组,所以可以修改*methodLists的值来增加成员方法,虽没办法扩展methodLists指向的内存区域,却可以改变这个内存区域的值(存储的是指针)。因此,可以动态添加方法,不能添加成员变量。
3、Category的实现原理或者本质 ?
- Category编译之后的底层结构是struct category_t,里面存储着分类的对象方法、类方法、属性、协议信息
- 在程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)
4、Category(分类)和Extension(扩展)的区别是什么?
- Extension在编译的时候,它的数据就已经包含在类信息中
- Category是在运行时,才会将数据合并到类信息中
- Extension可以添加实例变量,而Category不可以。
- Extension和Category都可以添加属性,但是Category的属性不能生成成员变量和getter、setter方法的实现。
5、load方法是什么时候调用的?load 方法能继承吗?
- load方法在runtime加载类、分类的时候调用
- load方法可以继承,但一般情况下不会主动去调用load方法,都是让系统自己调用
6、Category的加载处理过程是什么?
- 通过Runtime加载某个类的所有Category数据
- 把所有Category的方法、属性、协议数据,合并到一个大数组中,
后面参与编译的Category数据,会在数组的前面 - 将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面
7、Category的+load方法调用顺序是什么?
- +load方法会在runtime加载类、分类时调用
- 每个类、分类的+load,在程序运行过程中只调用一次
- 先调用类的+load
1、按照编译先后顺序调用(先编译,先调用)
2、调用子类的+load之前会先调用父类的+load - 再调用分类的+load
1、按照编译先后顺序调用(先编译,先调用)
8、