关联属性
思考, 如何实现给分类"添加成员变量"?
默认情况下, 因为分类底层结构的限制, 不能添加成员变量到分类中. 但可以通过关联对象来间接实现
关联对象提供了以下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)
Key
的常见用法
static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)
static char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)
使用属性名作为key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, @"property");
使用get
方法的@selecor
作为key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, @selector(getter))
或者用
objc_getAssociatedObject(self, _cmd)
一般用第四种: 使用get
方法的@selecor
作为key
再来看一下: objc_AssociationPolicy
图片来源小码哥
我们看下objc_setAssociatedObject
底层究竟做了些什么:
直接调用了_object_set_associative_reference
:
所以, 这个数据存储的流程就是:
运行时全局维护了一个AssociationsManager
管理类, 那么这个管理类里又有一个AssociationsHashMap
这个AssociationsHashMap
是通过object
为key存储数据的, 也就是说, 一个对象对应一条数据, 那么每个关联的对象都对应一条数据.
这条数据就又是一个hashMap
, 即: ObjectAssociationMap
那么ObjectAssociationMap
里面又是什么呢?
ObjectAssociationMap
以你传入的key
为key
, 值是由你传入的policy
和value
组成的结构体为值
如下图所示:
图片来源小码哥
如果设置value
为nil
, 会移除掉这个key吗?
如果通过
key
找到了, 就会直接删除这个value
, 如果整个关联对象中已经不存在需要关联的值, 那就会把整个关联对象都删掉.
我们再来看看objc_getAssociatedObject
内部调用了_object_get_associative_reference
可以很清楚的看到逻辑:
-
先通过
object
, 找到associations
这个hashmap
里的值, 也是一个hashmap
, 叫做ObjectAssociationMap
-
再通过
key
找到refs
里的值, 就是association
, 里面存储了policy
和value
值, 最后返回的是association
里的autoreleaseReturnedValue
值.
而移除所有关联对象, objc_removeAssociatedObjects
就是根据object
为key
, 找到对应的hashMap
, 然后再删掉, 如下图所示: