美文网首页Object-cObjective - C 底层
Objective - C 关联对象(二) 关联对象的底层数据结

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

作者: 爱玩游戏的iOS菜鸟 | 来源:发表于2020-04-20 17:04 被阅读0次

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

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

    • 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 关联对象(二) 关联对象的底层数据结

        本文链接:https://www.haomeiwen.com/subject/fzvdihtx.html