美文网首页
十四、关联对象

十四、关联对象

作者: Mjs | 来源:发表于2020-10-22 18:27 被阅读0次

    分类与类扩展

    1. category∶类别,分类
    • 专门用来给类添加新的方法
    • 不能给类添加成员属性,添加了成员变量,也无法取到
    • 注意∶其实可以通过runtime给分类添加属性
    • 分类中用 @property 定义变量,只会生成变量的 getter,setter 方法的声明,不能生成方法实现和带下划线的成员变量。
    1. extension∶类扩展
    • 可以说成是特殊的分类,也称作匿名分类
    • 可以给类添加成员属性,但是是私有变量
    • 可以给类添加方法,也是私有方法

    在分类中我们只能通过runtime给分类添加属性

    - (void)setCate_name:(NSString *)cate_name{
        /**
         1: 对象
         2: 标识符
         3: value
         4: 策略
         */
        objc_setAssociatedObject(self, "cate_name", cate_name, OBJC_ASSOCIATION_COPY_NONATOMIC);
    }
    
    - (NSString *)cate_name{
        return  objc_getAssociatedObject(self, "cate_name");
    }
    

    objc_setAssociatedObject到底做了什么呢,我们随着源码一探究竟

    void
    objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    {
        SetAssocHook.get()(object, key, value, policy);
    }
    
    static ChainedHookFunction<objc_hook_setAssociatedObject> SetAssocHook{_base_objc_setAssociatedObject};
    
    static void
    _base_objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    {
      _object_set_associative_reference(object, key, value, policy);
    }
    
    

    我们最好找到了方法实现的地方_object_set_associative_reference

    void
    _object_set_associative_reference(id object, const 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;
    
        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));
        // 包装了一下 对象
        DisguisedPtr<objc_object> disguised{(objc_object *)object};
        // 包装一下 policy - value
        ObjcAssociation association{policy, value};
    
        // retain the new value (if any) outside the lock.
        association.acquireValue();
    
        {
            AssociationsManager manager;
        
            AssociationsHashMap &associations(manager.get());
    
            if (value) {
                auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
                if (refs_result.second) {
                    /* it's the first association we make */
                    object->setHasAssociatedObjects();
                }
    
                /* establish or replace the association */
                auto &refs = refs_result.first->second; // 空的桶子
                auto result = refs.try_emplace(key, std::move(association));向空的桶子里插入
                if (!result.second) {
                    association.swap(result.first->second);
                }
            } else {//value没有
                auto refs_it = associations.find(disguised);
                if (refs_it != associations.end()) {
                    auto &refs = refs_it->second;
                    auto it = refs.find(key);
                    if (it != refs.end()) {
                        association.swap(it->second);
                        refs.erase(it);//消除
                        if (refs.size() == 0) {
                            associations.erase(refs_it);//消除
    
                        }
                    }
                }
            }
        }
    
        // release the old value (outside of the lock).
        association.releaseHeldValue();
    }
    

    disguised就是对object进行了包装一下,associationpolicyvalue进行了包装

        inline void acquireValue() {
            if (_value) {
                switch (_policy & 0xFF) {
                case OBJC_ASSOCIATION_SETTER_RETAIN:
                    _value = objc_retain(_value);
                    break;
                case OBJC_ASSOCIATION_SETTER_COPY:
                    _value = ((id(*)(id, SEL))objc_msgSend)(_value, @selector(copy));
                    break;
                }
            }
        }
    

    acquireValuevalue 根据policy进行了处理

    class AssociationsManager {
        using Storage = ExplicitInitDenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap>;
        static Storage _mapStorage;
    
    public:
        AssociationsManager()   { AssociationsManagerLock.lock(); }
        ~AssociationsManager()  { AssociationsManagerLock.unlock(); }
    
        AssociationsHashMap &get() {
            return _mapStorage.get();
        }
    
        static void init() {
            _mapStorage.init();
        }
    };
    

    manager只是加了个锁,而associations是从manager. get()获取的,_mapStorage是一个静态变量,所以AssociationsHashMap获取同一个表

      template <typename... Ts>
      std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
        BucketT *TheBucket;
        if (LookupBucketFor(Key, TheBucket))  // 找桶子
          return std::make_pair(
                   makeIterator(TheBucket, getBucketsEnd(), true),
                   false); // Already in map.
    
        // Otherwise, insert the new element.
        TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
        return std::make_pair(
                 makeIterator(TheBucket, getBucketsEnd(), true),
                 true);
      }
    

    定义个空的桶子,首先去寻找,找到,就返回false,没找到,插入个桶子返回true

    
            if (value) {
                auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});//先查询总表
                if (refs_result.second) {
                    /* it's the first association we make */
                    object->setHasAssociatedObjects();
                }
    
                /* establish or replace the association */
                auto &refs = refs_result.first->second; // 空的桶子
                auto result = refs.try_emplace(key, std::move(association));向空的桶子里插入
                if (!result.second) {
                    association.swap(result.first->second);
                }
            } 
    
    bucket.png

    请问关联对象是否需要移除

    - (void)dealloc {
        _objc_rootDealloc(self);
    }
    
    void
    _objc_rootDealloc(id obj)
    {
        ASSERT(obj);
    
        obj->rootDealloc();
    }
    
    inline void
    objc_object::rootDealloc()
    {
        if (isTaggedPointer()) return;  // fixme necessary?
    
        if (fastpath(isa.nonpointer  &&  
                     !isa.weakly_referenced  &&  
                     !isa.has_assoc  &&  
                     !isa.has_cxx_dtor  &&  
                     !isa.has_sidetable_rc))
        {
            assert(!sidetable_present());
            free(this);
        } 
        else {
            object_dispose((id)this);
        }
    }
    
    id 
    object_dispose(id obj)
    {
        if (!obj) return nil;
    
        objc_destructInstance(obj);    
        free(obj);
    
        return nil;
    }
    void *objc_destructInstance(id obj) 
    {
        if (obj) {
            // Read all of the flags at once for performance.
            bool cxx = obj->hasCxxDtor();
            bool assoc = obj->hasAssociatedObjects();
    
            // This order is important.
            if (cxx) object_cxxDestruct(obj);
            if (assoc) _object_remove_assocations(obj);
            obj->clearDeallocating();
        }
    
        return obj;
    }
    
    void
    _object_remove_assocations(id object)
    {
        ObjectAssociationMap refs{};
    
        {
            AssociationsManager manager;
            AssociationsHashMap &associations(manager.get());
            AssociationsHashMap::iterator i = associations.find((objc_object *)object);
            if (i != associations.end()) {
                refs.swap(i->second);
                associations.erase(i);
            }
        }
    
        // release everything (outside of the lock).
        for (auto &i: refs) {
            i.second.releaseHeldValue();
        }
    }
    
    

    析构的时候都会移除掉

    相关文章

      网友评论

          本文标题:十四、关联对象

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