其中的几个类和数据结构,具体分析了解其中它们的作用:
AssociationsManager
AssociationsHashMap
spinlock_t AssociationsManagerLock;
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;
}
};
AssociationsHashMap *AssociationsManager::_map = NULL;
它维护了 spinlock_t
和 AssociationsHashMap
的单例,初始化它的时候会调用 lock.lock()
方法,在析构时会调用 lock.unlock()
,而 associations
方法用于取得一个全局的 AssociationsHashMap
单例。
也就是说 AssociationsManager
通过持有一个自旋锁 spinlock_t
保证对 AssociationsHashMap
的操作是线程安全的,即每次只会有一个线程对 AssociationsHashMap 进行操作。
首先,AssociationsHashMap 用与保存从对象的 disguised_ptr_t 到 ObjectAssociationMap 的映射:
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); }
};
而 ObjectAssociationMap 则保存了从 key 到关联对象 ObjcAssociation 的映射,这个数据结构保存了当前对象对应的所有关联对象:
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); }
};
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; }
};
大概的存放结构图

接下来我们可以重新回到对 objc_setAssociatedObject
方法的分析了。
在这里会将方法的执行分为两种情况:
-
new_value != nil
设置/更新关联对象的值 -
new_value == nil
删除一个关联对象
new_value != nil
先来分析在 new_value != nil 的情况下,该方法的执行是什么样的:
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
ObjcAssociation old_association(0, nil);
id new_value = value ? acquireValue(value, policy) : nil;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
j->second = ObjcAssociation(policy, new_value);
} else {
(*refs)[key] = ObjcAssociation(policy, new_value);
}
} else {
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
}
}
if (old_association.hasValue()) ReleaseValue()(old_association);
}
1.使用 old_association(0, nil) 创建一个临时的 ObjcAssociation 对象(用于持有原有的关联对象,方便在方法调用的最后释放值)
2.调用 acquireValue 对 new_value 进行 retain 或者 copy
static id acquireValue(id value, uintptr_t policy) {
switch (policy & 0xFF) {
case OBJC_ASSOCIATION_SETTER_RETAIN:
return ((id(*)(id, SEL))objc_msgSend)(value, SEL_retain);
case OBJC_ASSOCIATION_SETTER_COPY:
return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
}
return value;
}
3.初始化一个 AssociationsManager,并获取唯一的保存关联对象的哈希表 AssociationsHashMap
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
4.先使用 DISGUISE(object) 作为 key 寻找对应的 ObjectAssociationMap
5.如果没有找到,初始化一个 ObjectAssociationMap,再实例化 ObjcAssociation 对象添加到 Map 中,并调用 setHasAssociatedObjects 方法,表明当前对象含有关联对象
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
6.如果找到了对应的 ObjectAssociationMap,就要看 key 是否存在了,由此来决定是更新原有的关联对象,还是增加一个
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
j->second = ObjcAssociation(policy, new_value);
} else {
(*refs)[key] = ObjcAssociation(policy, new_value);
}
7.最后的最后,如果原来的关联对象有值的话,会调用 ReleaseValue() 释放关联对象的值
struct ReleaseValue {
void operator() (ObjcAssociation &association) {
releaseValue(association.value(), association.policy());
}
};
static void releaseValue(id value, uintptr_t policy) {
if (policy & OBJC_ASSOCIATION_SETTER_RETAIN) {
((id(*)(id, SEL))objc_msgSend)(value, SEL_release);
}
}
new_value == nil
如果 new_value == nil
,就说明我们要删除对应 key
的关联对象,实现如下:
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
ObjcAssociation old_association(0, nil);
id new_value = value ? acquireValue(value, policy) : nil;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
refs->erase(j);
}
}
}
if (old_association.hasValue()) ReleaseValue()(old_association);
}
这种情况下方法的实现与前面的唯一区别就是,我们会调用 erase
方法,擦除 ObjectAssociationMap
中 key
对应的节点。
setHasAssociatedObjects()
其实上面的两种情况已经将 objc_setAssociatedObject 方法的实现分析得很透彻了,不过,这里还有一个小问题来等待我们解决,setHasAssociatedObjects() 方法的作用是什么?
inline void objc_object::setHasAssociatedObjects() {
if (isTaggedPointer()) return;
retry:
isa_t oldisa = LoadExclusive(&isa.bits);
isa_t newisa = oldisa;
if (!newisa.indexed) return;
if (newisa.has_assoc) return;
newisa.has_assoc = true;
if (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)) goto retry;
}
它会将 isa 结构体中的标记位 has_assoc 标记为 true,也就是表示当前对象有关联对象,在这里我还想祭出这张图来介绍 isa 中的各个标记位都是干什么的。

关于实现
关联对象又是如何实现并且管理的呢:
- 关联对象其实就是 ObjcAssociation 对象
- 关联对象由 AssociationsManager 管理并在 AssociationsHashMap 存储
- 对象的指针以及其对应 ObjectAssociationMap 以键值对的形式存储在 AssociationsHashMap 中
ObjectAssociationMap 则是用于存储关联对象的数据结构 - 每一个对象都有一个标记位 has_assoc 指示对象是否含有关联对象
参考:
网友评论