美文网首页
聊一聊weak

聊一聊weak

作者: 晨阳Xia | 来源:发表于2020-12-11 12:29 被阅读0次

1.聊一聊附有__weak修饰符的变量背添加到弱引用表,以及在弱引用表中删除的过程

附有__weak修饰符的变量,指向一个alloc生成的对象,编译之后的代码


image.png

编译前:

{
    id __weak obj1 = obj;
}

编译后:

id obj1;
/*
location:附有__weak修饰符的变量
newObj:被引用的对象
*/

1.

objc_initWeak(id *location, id newObj) {
   if (!newObj) {
        *location = nil
        return nil
   }
   
   return storeWeak<false/*old*/, true/*new*/,  true/*crash*/>(location, (objc_object*)newObj)
}

2.

storeWeak(id *location, id newObj) {
    ...
    SideTable *oldTable;
    SideTable *newTable;
    
    ...
    newTable = &SideTables()[newObj] // 以对象为键值,在散列表中中找到newTable
    
    ...
    newObj = (objc_bjectt)weak_register_no_lock(&newTable->weak_table,(id)newObj,location,CrashIfDellocating)
    
    ...
    // 赋值
    *location = (id)newObj
}

3.
/*
    referent_id:被引用的对象
    *referrer_id:附有__weak修饰符的变量
*/

weak_register_no_lock(weak_table *weak_table, id referent_id, id *referrer_id, bool crashIfDellocating) {
    objc_object *referent = (objc_object *)referent_id;
    objc_object *referrer = (objc_object **)referrer_id;
    
    ...
    weak_entry *entry; // 弱引用数组(理解为数组,其实比数组更复杂)
    if (entry = weak_entry_for_referent(weak_table, referent)) {
        append_referrer(entry, referrer);
    } else { // 没有则创建
        weak_entry_t *new_entry;
        new_entry.referent = referent;
        new_entry.out_of_line = ;
        new_entry.inline_referrer[0] = referrer;
        for (i = 1; i < WEAK_INLINE_COUNT; i++) {
                new_entry.inline_referrer[i] = nil;
        }
    }
    
    weak_grow_maybe(weak_table);
    // 将数组插入散列表中
    weak_insert_entry(weak_table, &new_entry);
}

4.
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent) {
    weak_entry_t weak_entries = weak_table->weak_entries;
    if (!weak_entries) {
        retrun nil;
    }
    
    ...
    
    size_t index = hash_pointer(referent) & weak_table->mash;
    // 哈希冲突
    // 当前索引拿到的对象不是传入referent,则索引加1,往下查找。
    while (weak_table->weak_entries[index].referent != referent) {
        index = (index+1) & weak_table->mask;
        hash_displacement++;
        if (hash_displacement > weak_table->max_hash_displacement) {
            return nil;
        }
    }
    
    ...
    return &weak_table->entries[index]
    
    
}

2.objc_initWeak 内部调用 objc_storeWeak函数

obj1 = 0
objc_storeWeak(&obj1, obj)

变量作用域结束时,调用以下函数销毁:

objc_destroyWeak(&obj1, 0);

2.objc_destroyWeak 内部调用 objc_storeWeak函数

objc_storeWeak(&obj1, 0)

2.若附有__weak修饰符的变量所引用的对象被废弃,则将该变量赋值为nil

weak_clear_no_lock(weak_table_t *weak_table, id referent_id){
    objc_object *referent = (objc_object *)referent_id;
    weak_entry_t *entry = weak_entry_for_refetent(weak_table, referent);
    if (!entry) {
        retrun nil;
    }
    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;
    }
    // 将引用对象的所有变量都置为nil
    for (size_t = 0; i < count; i++) {
        objc_object **referrer = referrers[i];
        if (referrer) {
            if (*referrer == referent) {
                *referrer = nil;
            }
        }
    }
    
}

3.使用附有__weak修饰符的变量,即是使用注册到autoreleasepool中的对象

1.使用__weak 修饰符时,一下代码会引起警告:

{
    id __weak obj = [[NSObject alloc] init];
    NSLog(@"obj = %@", obj) // 结果: obj == (null)
}

/* 编译器的模拟代码 */
id obj1;
id tmp = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(tmp, @seletor(init));
objc_initWeak(&obj1, tmp);
objc_release(tmp)
objc_destoryWeak(&obj1)

虽然自己生成并持有的对象通过objc_initWeak函数被赋值给__weak修饰符的变量中,但编译器判断其没有持有者,故该对象立即通过objc_release函数被释放和废弃。

2.使用附有__weak修饰符的变量,即是使用注册到autoreleasepool中的对象

{
    id __weak obj1 = obj;
}
/* 编译器的模拟代码 */
id obj1;
objc_initWeak(&obj1, obj);
id tmp = objc_loadWeakRetained(&obj1)
objc_autorelease(tmp)
objc_destoryWeak(&obj1)

(1)objc_loadWeakRetained函数取出附有__weak修饰符变量所引用的对象并retain
(2) objc_autorelease函数将对象注册到autoreleasepool中
由此可知,因为附有__weak修饰符变量所引用的对象想这样被注册到aotureleasepool中 ,所以在@autoreleasepool块结束之前都可以放心的使用。但是如果大量的使用附有__weak修饰符的变量,注册到autoreleasasepool的对象也会大量的增加.因此在使用附有__weak修饰符的变量时,最好先暂时赋值给附有__strong修饰符的变量后再使用。
图片举例


image.png image.png

独自实现引用计数机制的类大多不支持__weak修饰符。

4.注意

大量使用附有__weak修饰符的变量,会消耗相应的cpu资源

参考文献

  • 《编写高质量iOS与OS X代码的52个有效方法》
  • 《Objective-C高级编程》

相关文章

  • 聊一聊weak

    1.聊一聊附有__weak修饰符的变量背添加到弱引用表,以及在弱引用表中删除的过程 附有__weak修饰符的变量,...

  • 聊一聊

    就是这样,喜欢自我欺骗,明知道,真心想你,或者有事的人,会打电话给你。却还是忍不住的用微信,看一个人的消息和动态,...

  • 聊一聊

    记录一下,现在是女儿的生日。2020.7.25星期六 生日快乐我的小天使 微淼商学院说过最经典的话是:有些做商学院...

  • 聊一聊

    早在三天前师兄就告知我们今天上午老师会和我们在实验室聊一聊。校园卡余额不足,时间紧张未吃早餐,早上慌忙收拾赶紧到实...

  • 聊一聊

    大家好,我是野生梅花鹿。 马上就12点了,我决定用几分钟的时间随便写点啥~ 首先呢,是反省。 这个月,其实懒惰了很...

  • 聊一聊

    很久没写了,聊聊最近发生的事,十月份开始了一段长板之旅,一开始担心害怕摔,因为通过挑战一个个动作,挺有趣的,当你为...

  • 聊一聊

    疫情这些年,常常听到的是,哪哪被封控了之类,作为天选打工人,一直在正常上班搬砖中。 直至上周五晚接...

  • 聊一聊自律

    很久以前就知道韩雪,当时只觉得她是气质很优雅,长得很美丽的女明星,没有什么特殊的感觉,应该就是花瓶而已。 她的才气...

  • 睡前聊一聊

    每天晚上睡觉前和小胤聊一聊,这是我目前最喜欢的事情了。听听他讲一讲幼儿园的所见所闻,觉得人生都充满了童趣。 昨天小...

  • 聊一聊寿险

    什么是寿险? 可以简单理解为死亡险,是在被保险人发生死亡后进行赔偿的保险。比如,45岁的Jack因为生病去世了,他...

网友评论

      本文标题:聊一聊weak

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