iOS的一个重要特性:runtime中一个重要功能就是关联对象。作用就是运行时动态的给对象添加变量。
那么runtime是如何实现动态添加的呢?直接上结论
关联对象并没有存放在对象的实体中,而是runtime维护了一个全局二维map来管理所有关联对象。
如果你对iOS实现过程不敢兴趣,那么你可以关闭这一篇文章了。但是如果你想了解可以继续看下去
来看看runtime源码,objc_setAssociatedObject的具体实现
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
// retain the new value (if any) outside the lock.
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);
if (new_value) {
// break any existing association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// secondary table exists
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 {
// create the new association (first time).
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
}
} else {
// setting the association to nil breaks the association.
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);
}
}
}
}
// release the old value (outside of the lock).
if (old_association.hasValue()) ReleaseValue()(old_association);
}
函数中涉及几个4个重要的数据结构:
AssociationsManager //管理全局AssociationsHashMap
AssociationsHashMap //存放对象的关联对象map的map(key为传入的object,value为map,也就是ObjectAssociationMap)
ObjectAssociationMap //存放关联对象的map(key为传入的key,value为关联对象)
ObjcAssociation //关联对象实体包含了value和policy两个重要信息(policy决定了value的内存管理方式)
文字介绍可能比较绕,引用一下另一位间书大神的文章的图
https://www.jianshu.com/p/4b463169a84a

四个结构图关系一目了然。所以:
runtime中维护了一个全局二维map来管理关联对象。
runtime除了还有一个objc_getAssociatedObject在这个二维map中取出关联对象外,还有一个objc_removeAssociatedObjects方法来移除某一个对象的所有关联对象。来看看源码:
void _object_remove_assocations(id object) {
vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
if (associations.size() == 0) return;
disguised_ptr_t disguised_object = DISGUISE(object);
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// copy all of the associations that need to be removed.
ObjectAssociationMap *refs = i->second;
for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
elements.push_back(j->second);
}
// remove the secondary table.
delete refs;
associations.erase(i);
}
}
// the calls to releaseValue() happen outside of the lock.
for_each(elements.begin(), elements.end(), ReleaseValue());
}
从源码可以看出也就是移除了对象的ObjectAssociationMap这个二级map。
网友评论