美文网首页
关联对象

关联对象

作者: 超级卡布达 | 来源:发表于2022-05-06 11:41 被阅读0次

    分类中不能添加成员变量

    默认情况下,因为分类底层结构的限制,分类中不能添加成员变量。如果强行添加会报错“Instance variables may not be placed in categories实例变量不能放在类别中实例变量不能放在类别中”如下图

    image.png
    如果通过@property (assign, nonatomic) int a;不会添加成员变量,只会生成(没有实现设值和取值)的setter和getter方法.

    通过关联对象变相的给分类“添加成员变量”

    设置关联对象

    objc_setAssociatedObject(id object, const void * key,
                             id value, objc_AssociationPolicy policy)
    

    获取关联对象

    objc_getAssociatedObject(id object, const void * key)
    

    移除类所有的关联对象

    objc_removeAssociatedObjects(id object)
    

    key的常见用法,保证key的唯一性

    取唯一的指针地址值
    static void *MyKey = &MyKey;
    objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, MyKey)
    static NSString *MyKey1;
    objc_setAssociatedObject(obj, &MyKey1, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, &MyKey1)
    使用属性名作为key
    objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_getAssociatedObject(obj, @"property");
    使用get方法的方法编号@selecor作为key
    objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, @selector(getter))
    

    objc_AssociationPolicy

    OBJC_ASSOCIATION_ASSIGN//assign
    OBJC_ASSOCIATION_RETAIN_NONATOMIC//strong,nonatomic
    OBJC_ASSOCIATION_COPY_NONATOMIC//copy, nonatomic
    OBJC_ASSOCIATION_RETAIN//strong,atomic
    OBJC_ASSOCIATION_COPY//copy,atomic
    
    关联对象的原理

    objc4源码解读`objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)

    void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
        _object_set_associative_reference(object, (void *)key, value, policy);
    }
    void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
        // 初始化第三个表。
        ObjcAssociation old_association(0, nil);
        id new_value = value ? acquireValue(value, policy) : nil;
        {
            AssociationsManager manager;
            第一个表AssociationsHashMap
            AssociationsHashMap &associations(manager.associations());
            disguised_ptr_t disguised_object = DISGUISE(object);//object作为key
            if (new_value) {
      
                //通过disguised_object取value值ObjectAssociationMap
                AssociationsHashMap::iterator i = associations.find(disguised_object);
                if (i != associations.end()) {//i不是最后一个
                    // 第二个表ObjectAssociationMap类表
                    ObjectAssociationMap *refs = i->second;
                    //ObjectAssociationMap对象表中通过key取出value值ObjcAssociation
                    ObjectAssociationMap::iterator j = refs->find(key);
                    if (j != refs->end()) {//j不是最后一个
                         //第三个表,ObjcAssociation类表
                        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 {
                // 设置关联为nil会移除关联值。
                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
    AssociationsHashMap//类表1
    ObjectAssociationMap//类表2
    ObjcAssociatio//类表3

    class AssociationsManager {
        static AssociationsHashMap *_map
    };
    类表1
    class AssociationsHashMap : public unordered_map<disguised_ptr_t(key), ObjectAssociationMap *(value)>
    类表2
    class ObjectAssociationMap : public std::map<void *(key), ObjcAssociation(value)>
    类表3
    class ObjcAssociation {
            uintptr_t _policy;//key
            id _value;//value
    };
    

    objc4源码解读:objc-references.mm

    原理图解: image.png

    相关文章

      网友评论

          本文标题:关联对象

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