美文网首页
iOS中weak源码

iOS中weak源码

作者: helinyu | 来源:发表于2022-02-22 18:19 被阅读0次
weak的数据结构 weak 定义调用过程
关键代码
template <HaveOld haveOld, HaveNew haveNew,
          enum CrashIfDeallocating crashIfDeallocating>
static id 
storeWeak(id *location, objc_object *newObj)
{
   newTable = &SideTables()[newObj]; // 通过里面的数据获取当前被引用的对象的table

    // Clean up old value, if any.
    if (haveOld) { // 去掉以前的旧的内容
        weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
    }

    // Assign new value, if any.
    if (haveNew) {
        // *关键用法* 注册新的弱引用
        newObj = (objc_object *)
            weak_register_no_lock(&newTable->weak_table, (id)newObj, location, 
                                  crashIfDeallocating ? CrashIfDeallocating : ReturnNilIfDeallocating);
        // weak_register_no_lock returns nil if weak store should be rejected
    }

    return (id)newObj;
}

/** 
 * Registers a new (object, weak pointer) pair. Creates a new weak
 * object entry if it does not exist.
 * 
 * @param weak_table The global weak table.
 * @param referent The object pointed to by the weak reference.  被引用的对象
 * @param referrer The weak pointer address. 弱引用指针地址
 */
id 
weak_register_no_lock(weak_table_t *weak_table, id referent_id, 
                      id *referrer_id, WeakRegisterDeallocatingOptions deallocatingOptions)
{
    objc_object *referent = (objc_object *)referent_id;
    objc_object **referrer = (objc_object **)referrer_id;

// 判断是不是对象
    if (referent->isTaggedPointerOrNil()) return referent_id;

    // now remember it and where it is being stored
    weak_entry_t *entry; // 已经有了这个
    if ((entry = weak_entry_for_referent(weak_table, referent))) {
        append_referrer(entry, referrer); // 添加进去就好了
    } 
    else {
// 没有的话,在weak_table 中插入一个新的数组
        weak_entry_t new_entry(referent, referrer);
        weak_grow_maybe(weak_table); // 是否需要扩充weak_table 的内容大小
        weak_entry_insert(weak_table, &new_entry);
    }

    // Do not set *referrer. objc_storeWeak() requires that the 
    // value not change.
    return referent_id;
}
// 添加弱引用对象
/** 
 * Add the given referrer to set of weak pointers in this entry.
 * Does not perform duplicate checking (b/c weak pointers are never
 * added to a set twice). 
 *
 * @param entry The entry holding the set of weak pointers. 
 * @param new_referrer The new weak pointer to be added.
 */
static void append_referrer(weak_entry_t *entry, objc_object **new_referrer)
{
    if (! entry->out_of_line()) {
        // 简略方式的添加
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            if (entry->inline_referrers[i] == nil) {
                entry->inline_referrers[i] = new_referrer;
                return;
            }
        }

        // Couldn't insert inline. Allocate out of line.
        weak_referrer_t *new_referrers = (weak_referrer_t *)
            calloc(WEAK_INLINE_COUNT, sizeof(weak_referrer_t));
        // This constructed table is invalid, but grow_refs_and_insert
        // will fix it and rehash it.
// 超过简略的部分, 这个部分需要设置为 全面的应用方式
        for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
            new_referrers[i] = entry->inline_referrers[i];
        }
        entry->referrers = new_referrers;
        entry->num_refs = WEAK_INLINE_COUNT;
        entry->out_of_line_ness = REFERRERS_OUT_OF_LINE;
        entry->mask = WEAK_INLINE_COUNT-1;
        entry->max_hash_displacement = 0;
    }

    ASSERT(entry->out_of_line());

// 是否需要扩充
    if (entry->num_refs >= TABLE_SIZE(entry) * 3/4) {
        return grow_refs_and_insert(entry, new_referrer);
    }

// 设置了弱引用
// 这里的hash算法,使用了开放地址线性寻址的方法
// hash算法实现了优化
    size_t begin = w_hash_pointer(new_referrer) & (entry->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    while (entry->referrers[index] != nil) {
        hash_displacement++;
        index = (index+1) & entry->mask;
        if (index == begin) bad_weak_table(entry);
    }
    if (hash_displacement > entry->max_hash_displacement) {
        entry->max_hash_displacement = hash_displacement;
    }
    weak_referrer_t &ref = entry->referrers[index];
    ref = new_referrer;
    entry->num_refs++;
}
// 没有数据的时候给weak_table 插入一个对象
/** 
 * Add new_entry to the object's table of weak references.
 * Does not check whether the referent is already in the table.
 */
static void weak_entry_insert(weak_table_t *weak_table, weak_entry_t *new_entry)
{
    weak_entry_t *weak_entries = weak_table->weak_entries;
    ASSERT(weak_entries != nil);

    size_t begin = hash_pointer(new_entry->referent) & (weak_table->mask);
    size_t index = begin;
    size_t hash_displacement = 0;
    while (weak_entries[index].referent != nil) {
        index = (index+1) & weak_table->mask;
        if (index == begin) bad_weak_table(weak_entries);
        hash_displacement++;
    }

//真实的插入
    weak_entries[index] = *new_entry;
    weak_table->num_entries++;

    if (hash_displacement > weak_table->max_hash_displacement) {
        weak_table->max_hash_displacement = hash_displacement;
    }
}
// 是否需要扩容

// weak_table 的扩容方式 0.75的时候扩容
// Grow the given zone's table of weak references if it is full.
static void weak_grow_maybe(weak_table_t *weak_table)
{
    size_t old_size = TABLE_SIZE(weak_table);

    // Grow if at least 3/4 full.
    if (weak_table->num_entries >= old_size * 3 / 4) {
        weak_resize(weak_table, old_size ? old_size*2 : 64);
    }
}

// 将旧的内容进行重新插入
static void weak_resize(weak_table_t *weak_table, size_t new_size)
{
    size_t old_size = TABLE_SIZE(weak_table);

    weak_entry_t *old_entries = weak_table->weak_entries;
    weak_entry_t *new_entries = (weak_entry_t *)
        calloc(new_size, sizeof(weak_entry_t));

    weak_table->mask = new_size - 1;
    weak_table->weak_entries = new_entries;
    weak_table->max_hash_displacement = 0;
    weak_table->num_entries = 0;  // restored by weak_entry_insert below
    
    if (old_entries) {
        weak_entry_t *entry;
        weak_entry_t *end = old_entries + old_size;
        for (entry = old_entries; entry < end; entry++) {
            if (entry->referent) {
                weak_entry_insert(weak_table, entry);
            }
        }
        free(old_entries);
    }
}

// 扩容entry_t 里面的弱引用的数组大小
/** 
 * Grow the entry's hash table of referrers. Rehashes each
 * of the referrers.
 * 
 * @param entry Weak pointer hash set for a particular object.
 */
__attribute__((noinline, used))
static void grow_refs_and_insert(weak_entry_t *entry, 
                                 objc_object **new_referrer)
{
    ASSERT(entry->out_of_line());

    size_t old_size = TABLE_SIZE(entry);
    size_t new_size = old_size ? old_size * 2 : 8;

    size_t num_refs = entry->num_refs;
    weak_referrer_t *old_refs = entry->referrers;
    entry->mask = new_size - 1;
    
    entry->referrers = (weak_referrer_t *)
        calloc(TABLE_SIZE(entry), sizeof(weak_referrer_t));
    entry->num_refs = 0;
    entry->max_hash_displacement = 0;
    
    for (size_t i = 0; i < old_size && num_refs > 0; i++) {
        if (old_refs[i] != nil) {
            append_referrer(entry, old_refs[i]);
            num_refs--;
        }
    }
    // Insert
    append_referrer(entry, new_referrer);
    if (old_refs) free(old_refs);
}

注意: 这里面的mask = 数目-1 , 因为我们的容量都是2的n次方俩计算的,所以,这个用来处理在这个里面 ,拓展:也可以通过这个方式来求余数% 。

// 在block里面经常会用到__weak 和__strong ,这样,block对这个变量就会出现了强引用, 所以,在block执行完成了之后,将新的strongSelf变量释放掉。


还需要处理的内容
SideTable 里面和对象之间是怎么映射的。
参考


参考0
store weak 参考

相关文章

  • iOS中weak源码

    关键代码 注意: 这里面的mask = 数目-1 , 因为我们的容量都是2的n次方俩计算的,所以,这个用来处理在这...

  • Runtime源码剖析---图解引用计数与weak

    Runtime源码剖析---图解引用计数与weak 在iOS开发过程中,会经常使用到一个修饰词“weak”,使用场...

  • block编程, __block, __weak, __stro

    参考:block编程iOS __weak和__strong在Block中的使用__block & __weak &...

  • iOS【copy,strong,retain,weak和assi

    摘录:iOS中copy,strong,retain,weak和assign的区别 copy,strong,weak...

  • iOS干货收集

    programming iOS - layer iOS中copy,strong,retain,weak和assig...

  • iOS weak源码详解

    准备工作 请准备好750.1版本的objc4源码一份【目前最新的版本】,打开它,找到文章中提到的方法,类型,对象 ...

  • ios weak 源码资料

    有空整理 摘要 isa 结构体 hasweaklyrefhas coxxsidetable_rcrefcount ...

  • iOS - weak 源码解析

    参考apple源码下载[https://opensource.apple.com/tarballs/]iOS底层学...

  • iOS- 基础性问题

    1、 weak和assign的区别? iOS开发中 weak和assign的区别[https://www.jian...

  • weak实现原理

    平时开发中我们经常会用到weak,但是它的实现原理也许不是很清楚,今天就从源码来探究一下(weak实现原理源码链接...

网友评论

      本文标题:iOS中weak源码

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