Objective - C 关联对象(二) 关联对象的底层数据结构

(一)分类 - 关联对象的原理

实现关联对象技术的核心对象有:

  • AssociationsManager
  • AssociationsHashMap
  • ObjectAssociationMap
  • ObjcAssociation

参考源码:objc-references.mm文件

(1)源码阅读顺序 (下面以set方法为例 get类似)
  1. 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);方法
  1. 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的定义,发现前面提到的四个对象是以如下结构进行关联的,去掉无关代码:

AssociationsManager

AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
结构关系

AssociationPolicyvalue封装成ObjcAssociation的结构,然后和key建立的映射关系构成ObjcAssociationMap,再对应由object的地址通过DISGUISE函数返回值生成的键存储在AssociationHashMap

其实,我们最开始解决添加"成员变量"的方法一和runtime的关联对象方法有写相似,相对而言这个更加完善,将所有的类的关联对象由AssociationsManager统一管理,并存储在AssociationHashMap中

因此,我们可以得出结论:

  • 关联对象并不是存储在被关联对象本身内存中
  • 关联对象由全局的统一的AssociationsManager管理并在AssociationHashMap中存储
  • 设置关联对象为nil,就相当于是移除关联对象

你可能感兴趣的:(Objective - C 关联对象(二) 关联对象的底层数据结构)