美文网首页iOS面试总结
OC语言之category_关联对象的本质源码解析

OC语言之category_关联对象的本质源码解析

作者: Jimmy_L_Wang | 来源:发表于2019-06-14 22:30 被阅读0次

    关联对象

    能否给分类添加"成员变量"?

    使用关联对象技术为分类添加"成员变量"

    关联对象添加的"成员变量"添加到了那里?

    关联对象的本质

    关联对象由系统提供的AssociationsManager类管理并在其成员变量AssociationsHashMap中存储。

    所有对象的关联内容都在同一个全局容器中(不同的类添加的分类成员变量也是放在这里)。

    关联对象的本质.png

    源码解析

    源码是objc-runtime.mm

    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);
        }
    }
    
    static id acquireValue(id value, uintptr_t policy) {
      //根据policy决定消息发送的类型
        switch (policy & 0xFF) {
        case OBJC_ASSOCIATION_SETTER_RETAIN:
            return objc_retain(value);
        case OBJC_ASSOCIATION_SETTER_COPY:
            return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
        }
        return value;
    }
    
    
    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;//见上面函数实现
        {
          //关联对象管理类,C++实现的一个类
            AssociationsManager manager;
          //获取其维护的一个Hashmap,我们可以理解为是一个字典
          //=============
          //是一个全局对象
          //=============
            AssociationsHashMap &associations(manager.associations());
          //DISGUISE函数对指针地址进行按位取反~,来作为全局容器当中某个对象的key
          //inline disguised_ptr_t DISGUISE(id value) { return ~uintptr_t(value); }
            disguised_ptr_t disguised_object = DISGUISE(object);
            if (new_value) {//value不为空
                // break any existing association.
              //根据对象指针查找对应的一个ObjectAssociationMap结构的Map
                AssociationsHashMap::iterator i = associations.find(disguised_object);
                if (i != associations.end()) { //找到
                    // 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 {//未找到
                    // create the new association (first time).
                    ObjectAssociationMap *refs = new ObjectAssociationMap;
                    associations[disguised_object] = refs;
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                    object->setHasAssociatedObjects();
                }
            } else {//value为空
                // 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); //擦除
                      //如果想撤销一个已经关联到对象的一个值时,可以采取value传值为nil的方式来实现
                    }
                }
            }
        }
        // release the old value (outside of the lock).
        if (old_association.hasValue()) ReleaseValue()(old_association);
    }
    
    关联对象的本质02.png

    相关文章

      网友评论

        本文标题:OC语言之category_关联对象的本质源码解析

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