iOS weak 指针实现原理2

作者: 大兵布莱恩特 | 来源:发表于2019-02-20 12:30 被阅读46次

    SideTable 结构如下

    struct SideTable {
        spinlock_t slock; ///线程同步锁
        RefcountMap refcnts; ///
        weak_table_t weak_table; /// weak 散列表 所有 weak 指针存放在这个表里
    };
    

    weak_table_t 结构如下

    struct weak_table_t {
        weak_entry_t *weak_entries;  ///指针数组 存放 weak_entry_t 类型
        size_t    num_entries; ///散列表最大可存放内容容量 
        uintptr_t mask; /// &mask 可以获取一个 key 从而在散列表快速查找某个元素 
        uintptr_t max_hash_displacement; ///hash key 最大偏移值
    };
    
    objc_object::clearDeallocating_slow()
    objc_object::clearDeallocating_slow()
    {
        assert(isa.nonpointer  &&  (isa.weakly_referenced || isa.has_sidetable_rc));
    
        SideTable& table = SideTables()[this];
        table.lock(); ///加锁
        if (isa.weakly_referenced) { /// 有弱引用指向 就将这个对象的指针置nil
            weak_clear_no_lock(&table.weak_table, (id)this);
        }
        ///对 isa 指针的引用技术管理
        if (isa.has_sidetable_rc) {
            table.refcnts.erase(this);
        }
        table.unlock(); ///解锁
    }
    
    

    weak_clear_no_lock(weak_table_t *weak_table, id referent_id)

    将 weak 散列表地址和当前对象实例传递进来

    weak_clear_no_lock(weak_table_t *weak_table, id referent_id) 
    {
        ///当前对象强转为 objc_object 结构体指针类型
        objc_object *referent = (objc_object *)referent_id;
        ///获weak散列表中跟当前对象对应的  weak_entry_t *结构体指针
        weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);
        if (entry == nil) { ///如果为 nil 代表 没有查找到这个对象在 weak 表里存放 可能是这个对象转成CF对象 并转移了对象引用计数所有权
            /// XXX shouldn't happen, but does with mismatched CF/objc
            //printf("XXX no entry for clear deallocating %p\n", referent);
            return;
        }
    
        // 存放所有 weak 指针数组
        weak_referrer_t *referrers;
        size_t count;
        
        if (entry->out_of_line()) {
            referrers = entry->referrers;
            count = TABLE_SIZE(entry);
        } 
        else {
            referrers = entry->inline_referrers;
            count = WEAK_INLINE_COUNT;
        }
        
        for (size_t i = 0; i < count; ++i) {
            objc_object **referrer = referrers[i];
           ///weak 指针数组中的元素 是 当前对象指向的指针地址 将指针置空 nil
            if (referrer) {
                if (*referrer == referent) {
                    *referrer = nil;
                }
                else if (*referrer) {
                    _objc_inform("__weak variable at %p holds %p instead of %p. "
                                 "This is probably incorrect use of "
                                 "objc_storeWeak() and objc_loadWeak(). "
                                 "Break on objc_weak_error to debug.\n", 
                                 referrer, (void*)*referrer, (void*)referent);
                    objc_weak_error();
                }
            }
        }
        ///从 weak 表中移除跟当前对象weak_entry_t有关的内容
        weak_entry_remove(weak_table, entry);
    }
    
    
    

    weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent) 根据当前对象指针作为查找条件从 weak_table_t 中获取 weak_entry_t * 指针类型结构体 这里边是一个简单的 hash 算法 用对象内存地址转成一个 hash 值 然后 & weak_table->mask 获得一个开始索引 然后根据这个索引在数组里查找元素 ,如果生成的索引查找的元素不是我们想要的 ,可以用 index + 1 & weak_table->mask 重新生成一个 index , 直到算出一个合适的索引 ,然后从数组里 取出 一个 weak_entry_t * 结构体指针

    static weak_entry_t *
    weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
    {
        assert(referent);
    
        weak_entry_t *weak_entries = weak_table->weak_entries;
    
        if (!weak_entries) return nil;
    ///用对象内存地址转成一个 hash 值 然后 & weak_table->mask 获得一个开始索引
        size_t begin = hash_pointer(referent) & weak_table->mask;
        size_t index = begin;
        size_t hash_displacement = 0;
        ///直到 index 对应的  weak_entries[index].referent ==  referent 是我们要释放掉的对象时 才会退出循环 
        while (weak_table->weak_entries[index].referent != referent) {
        /// 用 index + 1 方式 生成一个新的 index 继续在 weak_entries查找 
            index = (index+1) & weak_table->mask;
            if (index == begin) bad_weak_table(weak_table->weak_entries);
            hash_displacement++;
            if (hash_displacement > weak_table->max_hash_displacement) {
                return nil;
            }
        }
        ///根据计算出来的 index 取出一个weak_entry_t * 结构体指针
        return &weak_table->weak_entries[index];
    }
    

    好了,我是大兵布莱恩特,欢迎加入博主技术交流群,iOS 开发交流群

    QQ20180712-0.png

    相关文章

      网友评论

        本文标题:iOS weak 指针实现原理2

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