知识点
分类(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;// 实例属性列表
method_list_t *methodsForMeta(bool isMeta) {
if (isMeda) return classMethods;
else return instanceMethods;
}
property_list_t *propertiesForMeta(bool isMeta) {
if (isMeta) return nil;
else return instanceProperties;
}
}
- 分类添加的方法可以『覆盖』原方法
- 同名分类方法,谁生效取决于编译顺序
- 名字相同的分类,编译报错
分类的加载处理过程
- 编译的时候所有分类都变成单独的结构体
- 程序开始运行时,通过Runtime加载某个类的所有Category数据
- 把所有Category的方法、属性、协议数据,合并到一个大数组中
后面参与编译的Category数据,会在数组的前面 - 将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面
类拓展(class extension)
注意:这里讨论的是Objective-C的类拓展(class extension), Swift的extension跟这个完全不同。
拓展的功能
- 声明私有属性
- 声明私有成员变量
- 声明私有方法(意义不大,也许能辅助阅读)
拓展的特点
- 编译时决定
- 只以声明的形式存在,多数情况下寄生于宿主的.m文件中
- 不能为系统类添加拓展
关联对象
默认情况下,因为分类底层结构的限制(没有常见对象编译后的结构体中用于存储实例变量的struct objc_ivar_list *ivars
数组),不能添加成员变量到分类中。但可以通过关联对象来间接实现
关联对象提供了以下API
/// 添加关联对象
void objc_setAssociatedObject(id object, const void * key,
id value, objc_AssociationPolicy policy)
/// 获得关联对象
id objc_getAssociatedObject(id object, const void * key)
/// 移除所有的关联对象
void objc_removeAssociatedObjects(id object)
原理
关联对象并不是存储在被关联对象本身内存中
关联对象存储在全局的统一的一个AssociationsManager中
实现关联对象技术的核心对象有
- AssociationsManager
- AssociationsHashMap
- ObjectAssociationMap
- ObjcAssociation
objc4源码解读:objc-references.mm
objc_AssociationPolicy
- OBJC_ASSOCIATION_ASSIGN assign
- OBJC_ASSOCIATION_RETAIN_NONATOMIC strong, nonatomic
- OBJC_ASSOCIATION_COPY_NONATOMIC copy, nonaomic
- OBJC_ASSOCIATION_RETAIN strong atomic
- OBJC_ASSOCIATION_COPY copy atomic
key的常见用法
- 使用属性名作为key
- 使用get方法的@selecor作为key
面试题
- 在开发中,你用分类做了哪些事情?
- 声明私有方法
- 分解体积庞大的类文件
- 将Framework的私有方法公开化
-
分类和类拓展(class extension)的区别?
分类- 运行时决定
- 可以为系统类添加分类
拓展 - 编译后即合并,即编译时决定
- 不能为系统类添加拓展
分类中可以添加哪些内容?
- 实例方法
- 类方法
- 协议
- 属性(只有getter和setter,实例变量需要通过关联对象来实现)
- 为什么分类不能添加实例变量?
clang编译之后,每一个分类都生成一个结构体,结构体中有类方法,实例方法,协议和属性等数组,没有常见对象编译后的结构体中用于存储实例变量的struct objc_ivar_list *ivars 数组