关联对象的方法
runtime给我们提供了三个关于关联对象的方法,如下。点击查看如何添加关联对象
//设置关联对象的方法
OBJC_EXPORT void
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy);
//获取关联对象的方法
OBJC_EXPORT id _Nullable
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key);
//删除关联对象的方法
OBJC_EXPORT void
objc_removeAssociatedObjects(id _Nonnull object);
了解了这三个方法,我们需要先记住添加关联对象方法的四个参数,分别是object
、key
、value
、policy
,这四个参数的含义分别是:
1.object
源对象(一般用self)
2.key
关联时的用来标记是哪一个属性的key(因为你可能要添加很多属性,这里咱们填写的是&nameKey)
3.value
关联的对象(name)
4.policy
一个关联策略
关联对象的核心对象
首先我们要知道的是关联对象并不是存储在被关联对象本身内存中,它是统一存储在一个全局的AssociationsManager
中,而实现关联对象技术的核心对象有四个,分别是:
- AssociationsManager
- AssociationsHashMap
- ObjectAssociationMap
- ObjcAssociation
AssociationsManager
的结构
class AssociationsManager {
// associative references: object pointer -> PtrPtrHashMap.
static AssociationsHashMap *_map;
public:
AssociationsManager() { AssociationsManagerLock.lock(); }
~AssociationsManager() { AssociationsManagerLock.unlock(); }
AssociationsHashMap &associations() {
if (_map == NULL)
_map = new AssociationsHashMap();
return *_map;
}
};
其中static AssociationsHashMap *_map;
是我们真正要关心的内容,public
里面的内容是一个锁和如果没有AssociationsHashMap
对象就新创建一个并返回其地址。
AssociationsHashMap
的结构
class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap *, DisguisedPointerHash, DisguisedPointerEqual, AssociationsHashMapAllocator> {
public:
void *operator new(size_t n) { return ::malloc(n); }
void operator delete(void *ptr) { ::free(ptr); }
};
其中我们需要关心的参数有两个分别是disguised_ptr_t
和AssociationsManager
,其中disguised_ptr_t
是我们设置关联对象时的那个object
,并且这个object
在AssociationsManager
用作为key,ObjectAssociationMap
是存储的哪个对象,并作为value,这个对象里面可能有多个关联对象。
ObjectAssociationMap
的结构
class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator> {
public:
void *operator new(size_t n) { return ::malloc(n); }
void operator delete(void *ptr) { ::free(ptr); }
};
这里面我们需要关心的参数有两个分别是void *
和ObjcAssociation
,其中void *
是我们设置关联对象时传递的参数key
,这个key
也是我们某一个关联对象的key,而ObjcAssociation
就是我们最终关联的那个对象了。
ObjcAssociation
的结构
class ObjcAssociation {
uintptr_t _policy;
id _value;
public:
ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}
ObjcAssociation() : _policy(0), _value(nil) {}
uintptr_t policy() const { return _policy; }
id value() const { return _value; }
bool hasValue() { return _value != nil; }
};
这里面我们需要关心的参数有两个分别是uintptr_t _policy;
和id _value;
,其中_value
是我们关联对象的值,比如我们关联的是字符串,这个就是那个字符串,而_policy
就是关联的策略。
以上结构中,public:
里面都是该结构的一些方法,不必过度关心,下面为用一个图来表示整个结构的关系,我把设置关联对象的那个方法再次贴到下面,为了方便看,我会做好分行,且不写返回值void
objc_setAssociatedObject(id _Nonnull object,
const void * _Nonnull key,
id _Nullable value,
objc_AssociationPolicy policy);