_object_set_associative_reference(id object, constvoid *key, id value, uintptr_t policy) { // This code used to work when nil was passed for object and key. Some code // probably relies on that to not crash. Check and handle it explicitly. // rdar://problem/44094390 if (!object && !value) return;
if (object->getIsa()->forbidsAssociatedObjects()) _objc_fatal("objc_setAssociatedObject called on instance (%p) of class %s which does not allow associated objects", object, object_getClassName(object)); // 把关联对象object包装成一个DisguisedPtr类型的数据结构 DisguisedPtr<objc_object> disguised{(objc_object *)object}; // 把关联策略policy和具体关联的值value包装成一个ObjcAssociation的数据结构 ObjcAssociation association{policy, value};
// retain the new value (if any) outside the lock. // 根据不同的策略类型做相应的处理 association.acquireValue();
if (value) { // 根据关联的对象disguised去关联表associations中查找对应的ObjectAssociationMap类型的value,如果没有就创建一个插入到associations里面 auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{}); if (refs_result.second) { /* it's the first association we make */ isFirstAssociation = true; // 设置为true }
/* establish or replace the association */ auto &refs = refs_result.first->second; auto result = refs.try_emplace(key, std::move(association)); // 根据传入的key找到对应的bucket,替换掉原来的或者插入新的association,并且设置关联策略。 if (!result.second) { association.swap(result.first->second); } } else { // 如果value值为nil 通过传入的关联对象disguised找到相应的AssociationsHashMap auto refs_it = associations.find(disguised); if (refs_it != associations.end()) { auto &refs = refs_it->second; auto it = refs.find(key); // 通过传入的key去找到ObjectAssociation if (it != refs.end()) { association.swap(it->second); // 进行擦除操作 refs.erase(it); if (refs.size() == 0) { associations.erase(refs_it);
} } } } }
// Call setHasAssociatedObjects outside the lock, since this // will call the object's _noteAssociatedObjects method if it // has one, and this may trigger +initialize which might do // arbitrary stuff, including setting more associated objects. if (isFirstAssociation) // 如果有关联对象 object->setHasAssociatedObjects();
// release the old value (outside of the lock). // 对association进行一次release操作 association.releaseHeldValue(); }
从上面我们可以看到设置关联的四个主要对象:
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
其中,AssociationsManager的结构为:
class AssociationsManager { using Storage = ExplicitInitDenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap>; static Storage _mapStorage; AssociationsHashMap &get() { return _mapStorage.get(); }