一个分类对应一个结构体指针对象,包含了分类中的一些信息
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 _property_list_t *protocols; // 分类中的协议列表
const struct _prop_list_t *properties; // 分类中的属性列表
...
}
程序在编译的时候就会创建分类对应的结构体指针变量,将信息存放在变量中,
但是只有在运行时才会将分类中的对象方法,类方法等合并到类对象,元类对象中
Category的加载处理过程
- 通过
Runtime
加载某个类的所有Category
数据 - 把所有的
Category
的方法、属性、协议数据,合并到一个大数组中(后面参与编译的Category数据,会在数组的前面) - 将合并后的分类数据(方法、属性、协议),插入到类原来数据前面
类扩展(Extension)和协议的区别:
- 分类是在运行时把分类信息合并到类信息中,而扩展是在编译时把信息合并到类信息中
- 分类声明的属性,只会生成
getter/setter
方法,不会自动生成成员变量和方法的实现,而扩展会 - 分类不可以添加实例变量,而扩展可以
- 分类可以为类添加方法的实现,而扩展只能声明,不能实现
分类的局限性
- 无法为类添加实例变量,但可以通过关联对象实现
- 分类中的方法若和类中原本的方法重名,会覆盖元类的方法,注:并不是真正的覆盖,只是runtime在查找方法的时候因为分类排在前面,所以会先找到,后面的不在查找
- 多个分类方法重名,会调用最后编译的那个分类中的方法
网友评论