千家信息网

Weak关键字介绍

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,由浅入深先来看看最简单的一个例子:#import "ViewController.h"@interface ViewController ()@property (nonatomic,strong)i
千家信息网最后更新 2026年10月31日Weak关键字介绍
由浅入深

先来看看最简单的一个例子:

#import "ViewController.h"@interface ViewController ()@property (nonatomic,strong)id strongPoint;@property (nonatomic,weak)id weakPoint;@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];//    self.strongPoint = [NSDate date];    self.strongPoint = [[UILabel alloc] init];    self.weakPoint = self.strongPoint;    self.strongPoint = nil;    NSLog(@"result is :%@", self.weakPoint);}@end

我们可以看到此时输出的结果为:

2017-02-07 13:20:41.119278 Test[7341:2187477] result is :(null)

如果我们使用的strong来修饰weakPoint,此时输出的结果为:

2017-02-07 13:23:13.211164 Test[7344:2187993] result is :>

如果我们使用assign来修饰weakPoint,此时运行程序可能会崩溃(因为如果引用操作发生时内存还没有改变内容,依旧可以输出正确结果,如果引用的时候内存内容发生改变了,就会crash),因为当assign指针所指向的内存被释放之后,不会自动赋值为nil,这样再次引用该指针的时候就会导致野指针操作。
对上述代码运行结果进行分析:
当使用weak关键字的时候,不会增加对象的计数,而且当所指对象置nil的时候,使用weak修饰的指针将被赋值为nil;
当使用strong关键字的时候,会增加对象的计数,也就是说会保持对象值的存在,所以当使用strong的时候weakPoint还会有值。
因此,我们从这里可以得出一个结果:
strong是强引用,它会保持对象值的存在;
weak是弱引用,当weak指针指向的对象摧毁之后,属性值也会清空(nil out)。
(注意:使用 _ _ weak修饰 和在@ property里面设置weak是一样的)
但是当我们执行如下代码的时候:

__strong NSString *yourString = @"Your String"; __weak NSString *myString = yourString;yourString = nil;__unsafe_unretained NSString *theirString = myString;NSLog(@"%p %@", yourString, yourString);NSLog(@"%p %@", myString, myString);NSLog(@"%p %@", theirString, theirString);

你会发现只有yourString为空,其他两个都不为空,这个是为什么呢?原因如下


这里是因为字符字面值永远不会被释放,所以你的weak指针还是指向它。
当你使用@""创建一个string对象的时候,它就是一个字面值,永远不会被改变。如果你在程序中很多地方都用到了一样的字符串,那么你可以测试一下,它们都是同一个对象(地址一样),String字面值不会销毁。使用[[NSString alloc] initWithString:@"literal string"]也是一样的效果。因为它指向了一个字面值的string。


那么请问weak指针指向对象被回收的时候该指针是如何被自动置为nil的呢??


首先,大家可以看一下博客最后面的附录,里面有两个文档,严格来说是Apple的opensouce。里面有一个objc-weak的类。这里是一个objc-weak.h类和一个objc-weak.mm类。

扩展常识.m和.mm的区别.m:源代码文件,这个典型的源代码文件扩展名,可以包含OC和C代码。.mm:源代码文件,带有这种扩展名的源代码文件,除了可以包含OC和C代码之外,还可以包含C++代码。仅在你的OC代码中确实需要使用C++类或者特性的时候才用这种扩展名。

从.h中可以看到以下几个关键的两个结构体:weak_entry_t和weak_table_t,以及一些方法。接下来简单介绍一下weak如何自动置为nil。
weak的实现其实是一个weak表,该表是一个由自旋锁管理的哈希表。
以下是从NSObject.mm里面摘出的一些方法:

idobjc_initWeak(id *location, id newObj){    if (!newObj) {        *location = nil;        return nil;    }    return storeWeak        (location, (objc_object*)newObj);}

该function的作用是初始化一个新的weak指针指向对象的地址。其中的参数介绍如下:

  • location段:_ _ weak指针的地址

  • newObj:对象的指针地址

这里调用的storeWeak方法,storeWeak方法里面通过template模板的参数进行更新weak操作,看源码可以知道里面会调用weak_register_no_lock/weak_unregister_no_lock等objc-weak.mm里面的方法进行相应的操作。objc-weak.h里面有句话:

For ARR, we also keep track of whether an arbitrary object is being deallocated by briefly placing it in the table just prior to invoking dealloc, and removing it via objc_clear_deallocating just prior to memory reclamation.

对象被废弃时最后调用objc_clear_deallocating。该函数实现如下:

void objc_clear_deallocating(id obj) {    assert(obj);    assert(!UseGC);    if (obj->isTaggedPointer()) return;    obj->clearDeallocating();}

也就是调用了clearDeallocating,继续追踪可以发现,它最终是使用了迭代器来取weak表的value,然后调用weak_clear_no_lock,然后查找对应的value,将该weak指针置空:

/**  * Called by dealloc; nils out all weak pointers that point to the  * provided object so that they can no longer be used. *  * @param weak_table  * @param referent The object being deallocated.  */void 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_referent(weak_table, referent);    if (entry == nil) {        /// XXX shouldn't happen, but does with mismatched CF/objc        //printf("XXX no entry for clear deallocating %p\n", referent);        return;    }    // zero out references    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];        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_entry_remove(weak_table, entry);}

objc_clear_deallocating该函数的动作如下:

  1. 从weak表中获取废弃对象的地址为键值的记录

  2. 将包含在记录中的所有附有 _ _ weak修饰符变量的地址,赋值为nil

  3. 将weak表中删除该记录

  4. 从引用计数表中删除废弃对象的地址为键值的记录
    看了objc-weak.mm的源码大概了解了:其实Weak表示一个hash表,然后里面的key是指向对象的地址,Value是Weak指针的地址的数组


对象 指针 时候 地址 指向 代码 方法 结果 文件 源代码 面值 关键 两个 内存 扩展名 输出 关键字 也就是 内容 函数 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网扶贫科技 互联网科技金融 喔噻互联网科技 互联网科技小贷 互联网与新科技 广西拼得多互联网科技有限公司 科技赋能互联网健康 江苏南京365互联网科技 科技互联网的估值 南山科技园互联网公司有哪些 搜狐科技互联网 恒生互联网科技指数跳水 米聚互联网科技南京有限公司排面 爱医互联网络科技 每天都有哪些好的互联网科技 山东大美朱楼互联网科技有限公司 上海乐五互联网科技有限公司 信承诺互联网科技有限公司 保山浩联互联网科技有限公司 中国主要互联网科技公司 天津市摩尔互联网科技 苏州找大状互联网科技有限公司 互联网科技工作委员会副主任毛军 互联网科技公司税收优惠 掌上梦互联网科技 互联网金融 科技创新 多迪互联网科技有限公司 深圳育鹏互联网科技有限公司招聘 996高科技互联网公司 合肥互联网科技公司公章图片
0