关键字 weak

364 阅读3分钟

weak基本用法

weak 关键字的作用弱引用,所引用对象的计数器不会加一,使得指针的访问是安全的;并在引用对象被释放的时候自动被设置为 nil

weak 的常见场景是在delegate,block,NSTimer中使用,以避免循环引用所带来的内存泄漏。

weak原理

weak表其实是一个哈希表,key是所指对象的指针,value是weak指针的地址数组。(value是数组的原因是:因为一个对象可能被多个弱引用指针指向) Runtime维护了一张weak表,用来存储某个对象的所有的weak指针。

weak原理实现过程:

1.初始化开始时,会调用objc_initWeak函数,初始化新的weak指针指向对象的地址
2.objc_initWeak函数里面会调用objc_storeWeak() 函数,objc_storeWeak() 函数的作用是用来更新指针的指向,创建弱引用表。
3.在最后会调用clearDeallocating函数。而clearDeallocating函数首先根据对象的地址获取weak指针地址的数组,然后紧接着遍历这个数组,将其中的数组开始置为nil,把这个entry从weak表中删除,最后一步清理对象的记录。

weak释放过程:

1、调用objc_release
2、因为对象的引用计数为0,所以执行dealloc
3、在dealloc中,调用了_objc_rootDealloc函数
4、在_objc_rootDealloc中,调用了object_dispose函数
5、调用objc_destructInstance
6、最后调用objc_clear_deallocating,详细过程如下:
   a. 从weak表中获取废弃对象的地址为键值的记录
   b. 将包含在记录中的所有附有 weak修饰符变量的地址,赋值为   nil
   c. 将weak表中该记录删除
   d. 从引用计数表中删除废弃对象的地址为键值的记录

拓展

weak,__unsafe_unretained, unowned 与 assign区别

__unsafe_unretained: 不会对对象进行retain,当对象销毁时,会依然指向之前的内存空间(野指针)

weak: 不会对对象进行retain,当对象销毁时,会自动指向nil

assign: 实质与__unsafe_unretained等同

unsafe_unretained也可以修饰代表简单数据类型的property,weak也不能修饰用来代表简单数据类型的property。

__unsafe_unretained 与 weak 比较,使用 weak 是有代价的,因为通过上面的原理可知,__weak需要检查对象是否已经消亡,而为了知道是否已经消亡,自然也需要一些信息去跟踪对象的使用情况。也正因此,__unsafe_unretained 比 __weak快,所以当明确知道对象的生命期时,选择__unsafe_unretained 会有一些性能提升,这种性能提升是很微小的。但当很清楚的情况下,__unsafe_unretained 也是安全的,自然能快一点是一点。而当情况不确定的时候,应该优先选用 __weak 。

unowned使用在Swift中,也会分 weak 和 unowned。unowned 的含义跟 __unsafe_unretained 差不多。假如很明确的知道对象的生命期,也可以选择 unowned。

weak应用

NSTimer 强引用

开启定时器后,testTimer方法将会一直运行,造成强引用。其中self变为weakSelf,并不能解决强引用,因为NSTimer的内部会对当前的weakSelf引用计数+1

self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(testTimerDeallo) userInfo:nil repeats:YES];

/** 方法一直执行 */
-(void)testTimer{

    NSLog(@"-----");
}

解决方法:使用block

    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf fire];
    }];

资料:segmentfault.com/a/119000001…

block

有意思的就在这里,IOS中,block内部,对弱应用的强引用,不会影响对象在外部的释放,同时,保证内部该对象也不会被提前释放。

__weak __typeof(self) weakSelf = self;

// block 内部
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) { return; }

weak singleton

此单例创建的强引用被销毁后,单例被销毁

+ (id)sharedInstance{

    static __weak ASingletonClass *instance;
    ASingletonClass *strongInstance = instance;
    @synchronized(self) {
        if (strongInstance == nil) {
            strongInstance = [[[self class] alloc] init];
            instance = strongInstance;
        }
    }
    return strongInstance;
}

参考资料: www.jianshu.com/p/f331bd5ce…