美文网首页
如何为分类(Category)添加成员变量

如何为分类(Category)添加成员变量

作者: 打碟的DJ | 来源:发表于2019-10-26 23:47 被阅读0次

    关联对象涉及的三个方法

    id objc_getAssociatedObject(id object, const void *key) {
        return _object_get_associative_reference(object, (void *)key);
    }
    
    
    void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
        _object_set_associative_reference(object, (void *)key, value, policy);
    }
    
    
    void objc_removeAssociatedObjects(id object) 
    {
        if (object && object->hasAssociatedObjects()) {
            _object_remove_assocations(object);
        }
    }
    

    关联对象的本质

    • 关联对象是由AssociationsManager管理并存储在AssociationsManager中
    • 所有对象的关联内容都是存储在同一个全局容器中
    关联对象.png

    源码分析

    /**
     * 关联对象
     * @param object
     * @param key
     * @param value 值
     * @param policy 策略
     * @by Si
     */
    void _object_set_associative_reference(id object, void *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;
        
        assert(object);
        
        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));
        
        // retain the new value (if any) outside the lock.
        ObjcAssociation old_association(0, nil);
        // 获取新的值
        id new_value = value ? acquireValue(value, policy) : nil;
        {
            // 关联对象管理类
            AssociationsManager manager;
            AssociationsManagerAssociationsManager &associations(manager.associations());
            // 按位取反,作为关联对象的key
            disguised_ptr_t disguised_object = DISGUISE(object);
            if (new_value) {
                // break any existing association.
                // 获取其维护的一个HashMap,是一个全局容器
                AssociationsHashMap::iterator i = associations.find(disguised_object);
                // 当前对象存在
                if (i != associations.end()) {
                    // secondary table exists
                    ObjectAssociationMap *refs = i->second;
                    ObjectAssociationMap::iterator j = refs->find(key);
                    // key存在直接赋值
                    if (j != refs->end()) {
                        old_association = j->second;
                        j->second = ObjcAssociation(policy, new_value);
                    } else {
                        // 不存在则生成一个ObjcAssociation
                        (*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);
    }
    

    关联对象的结构

    关联对象的结构图.png

    相关文章

      网友评论

          本文标题:如何为分类(Category)添加成员变量

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