类和分类的加载(下)

136 阅读2分钟

懒加载类的加载时机?

  1. 在main函数之后
  2. 在类被实例化后才加载

从堆栈信息来看

  1. 查找类的方法缓存cache
  2. 找到objc_msgSend_uncache
  3. 调用LookUpImporForward
  4. 调用realizeWithoutSwift,,初始化实例对象,加载类
  • 总结只有当类第一次收到消息的时候才会被初始化加载

分类的结构:

image.png

分类没有属性,也没有成员变量,需要通过关联对象的形式,实现属性 即实现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中,也就是编译时候就会加载