懒加载类的加载时机?
- 在main函数之后
- 在类被实例化后才加载
从堆栈信息来看
- 查找类的方法缓存cache
- 找到objc_msgSend_uncache
- 调用LookUpImporForward
- 调用realizeWithoutSwift,,初始化实例对象,加载类
- 总结只有当类第一次收到消息的时候才会被初始化加载
分类的结构:
分类没有属性,也没有成员变量,需要通过关联对象的形式,实现属性 即实现set和get方法
- 设置set方法(需要关联的对象,属性名称,属性值,关联策略)
static const char *NameKey = "NameKey"; -(void)setName:(NSString *)name { objc_setAssociatedObject(self, NameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC); }
-
关联属性存入一张全局唯一的HashMap中,
-
什么是hashmap?
-
Hashmap是通过key找到在内存中的位置的数据结构存储的是键值对(key : value)
-
通过AssociationsManager 加锁处理,保证同一时间只有一个线程在处理关联对象
-
表的结构是 DenseMap <DisguisedPtr<objc_object>, ObjectAssociationMap> AssociationsHashMap;
-
其中 DisguisedPtr:DisguisedPtr 关联对象
-
ObjectAssociationMap:关联策略、属性的值和属性名称
-
每次往hash表里面添加对象和其关联属性,通过遍历hash表来确定是否添加和替换
关联对象的get方法
- 参数(关联对象,关联属性名称) -(NSString *)name { return objc_getAssociatedObject(self, NameKey); }
- 通过 disguised 和key 从Hashmap中找到关联的属性值。 返回时将关联对象直接放到自动释放池association.autoreleaseReturnedValue(); 当对象释放的时候,关联的属性也从hashmap移除
分类加载的时机
- 1、只有当类和分类均为非懒加载类,ro里面没有分类方法,运行时创建rwe,将分类方法放入rwe中,将分类的方法放入方法列表的前面
- 2、也就是说类的实例方法和分类的方法重名时,使用分类方法,分类方法在类方法列表的前面
- 3、 类(是),分类(非懒),ro:既有 类方法 也有 分类方法也不会创建rwe
- 4、类(非懒),分类(是)同3
- 5、类(是)和分类(是) 同3 是首次被实例化的时候加载
rwe创建的时机: 1、使用runtimeAPI添加方法、属性协议等会创建rwe 2、类和分类都是非懒加载类时,创建rwe
总结:
- 如果是类和分类均为非懒加载的类,则在运行时被加载
- 如果分类是懒加载的,则在编译时候会把属性、方法等放入ro中,也就是编译时候就会加载