iOS weak 指针实现原理2

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 开发交流群

iOS weak 指针实现原理2_第1张图片

你可能感兴趣的:(iOS,开发,app,苹果,iOS,高级,设计模式,数据结构)