最近用到了sunnyxx的forkingdog系列《UIView-FDCollapsibleConstraints》,纪录下关联对象和MethodSwizzling在实际场景中的应用。
基本概念
关联对象
- 关联对象操作函数
- 设置关联对象:
123456789/*** 设置关联对象** @param object 源对象* @param key 关联对象的key* @param value 关联的对象* @param policy 关联策略*/void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)- 获取关联对象:
123456789/*** 获取关联对象** @param object 源对象* @param key 关联对象的key** @return 关联的对象*/id objc_getAssociatedObject(id object, const void *key)其中设置关联对象的策略有以下5种:
- 和MRC的内存操作retain、assign方法效果差不多
- 比如设置的关联对象是一个UIView,并且这个UIView已经有父控件时,可以使用OBJC_ASSOCIATION_ASSIGN
1 2 3 4 5 |
OBJC_ASSOCIATION_ASSIGN // 对关联对象进行弱引用 OBJC_ASSOCIATION_RETAIN_NONATOMIC // 对关联对象进行强引用(非原子) OBJC_ASSOCIATION_COPY_NONATOMIC // 对关联对象进行拷贝引用(非原子) OBJC_ASSOCIATION_RETAIN // 对关联对象进行强引用 OBJC_ASSOCIATION_COPY // 对关联对象进行拷贝引用 |
关联对象在一些第三方框架的分类中常常见到,这里在分析前先看下分类的结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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; }; |
从以上的分类结构,可以看出,分类中是不能添加成员变量的,也就是Ivar类型。所以,如果想在分类中存储某些数据
时,关联对象就是在这种情况下的常用选择。
需要注意的是,关联对象并不是成员变量
,关联对象是由一个全局哈希表
存储的键值对中的值。
全局哈希表的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class AssociationsManager { static spinlock_t _lock; static AssociationsHashMap *_map; // associative references: object pointer -> PtrPtrHashMap. public: AssociationsManager() { spinlock_lock(&_lock); } ~AssociationsManager() { spinlock_unlock(&_lock); } AssociationsHashMap &associations() { if (_map == NULL) _map = new AssociationsHashMap(); return *_map; } }; |
其中的AssociationsHashMap就是那个全局哈希表,而注释中也说明的很清楚了:哈希表中存储的键值对是(源对象指针 : 另一个哈希表)
。而这个value,即ObjectAssociationMap对应的哈希表如下:
1
其中设置关联对象的策略有以下5种:
关联对象在一些第三方框架的分类中常常见到,这里在分析前先看下分类的结构:
从以上的分类结构,可以看出,分类中是不能添加成员变量的,也就是Ivar类型。所以,如果想在分类中 需要注意的是, 全局哈希表的定义如下:
其中的AssociationsHashMap就是那个全局哈希表,而注释中也说明的很清楚了:哈希表中存储的键值对是
|