(一)分类 - 关联对象的原理
实现关联对象技术的核心对象有:
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
参考源码:objc-references.mm文件
(1)源码阅读顺序 (下面以set方法为例 get类似)
- objc-runtime.mm文件
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
- 调用
_object_set_associative_reference(object, (void *)key, value, policy);
方法
- objc-references.mm文件
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy)
重要方法分析:
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) {//如果set方法传值不是nil
// break any existing association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
//如果AssociationsHashMap已经存在 进行下一步
// 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 {
//AssociationsHashMap不存在 创建 并 添加
// create the new association (first time).
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
}
} else {
//如果set方法传值是nil
// 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);
}
我们深入进入AssociationsManager
的定义,发现前面提到的四个对象是以如下结构进行关联的,去掉无关代码:
AssociationPolicy
和value
封装成ObjcAssociation
的结构,然后和key
建立的映射关系构成ObjcAssociationMap
,再对应由object
的地址通过DISGUISE
函数返回值生成的键存储在AssociationHashMap
中
其实,我们最开始解决添加"成员变量"的方法一和runtime的关联对象方法有写相似,相对而言这个更加完善,将所有的类的关联对象由AssociationsManager统一管理,并存储在AssociationHashMap中
因此,我们可以得出结论:
- 关联对象并不是存储在被关联对象本身内存中
- 关联对象由全局的统一的AssociationsManager管理并在AssociationHashMap中存储
- 设置关联对象为nil,就相当于是移除关联对象
网友评论