美文网首页
__weak和__strong的使用

__weak和__strong的使用

作者: 最初九月雪 | 来源:发表于2017-12-23 12:30 被阅读28次

1. 使用场景

  一般我们在使用block的时候, 都会特意去注意一个问题--循环引用的问题, 根据OC的引用计数机制, 当对象的引用计数为0的时候, 系统会释放这个对象. 循环引用会导致我们的对象不能正常释放, 类似资源争夺的现象, 释放A的条件是B的释放, 而释放B的条件是释放A.

1.1 声明一个是TestViewController里面定义一个block--callBack

@interface TestViewController : UIViewController
@property (nonatomic, copy) void(^callBack)(NSString* name);
@end

1.2在viewDidLoad里面实现并调用block

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setCallBack:^(NSString *name) {
        NSLog(@"%@ %@", self, name);
    }];
    self.callBack(@"come on");
}
- (void)dealloc
{
    NSLog(@"%@ dealloc ", self);
}

这个代码里面是一个最基础的循环引用问题(测试贴图), 一般我们解决此类问题需要有一个弱引用也就是我们所要讲述的__weak,代码如下

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        NSLog(@"%@ %@", weakSelf, name);
    }];
    self.callBack(@"come on");
}

这样的话, TestViewController就可以正常的dealloc了.

2. 注意事项

这样写会存在一定的隐患, 因为__weak类型在这里是个局部变量, 而且weak属性有个特点就是自动置为nil, 所以有可能在我们去使用weakSelf的时候, weakSelf已经是空值了.

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@ %@", weakSelf, name);
        });
    }];
    self.callBack(@"come on");
}

输出结果是

2017-12-23 11:50:00.450854+0800 循环引用问题[5620:207264] <TestViewController: 0x7fc43ae025b0> dealloc
2017-12-23 11:50:02.952027+0800 循环引用问题[5620:207367] (null) come on

会先delloc, 然后才会走block里面的代码. 可以看到此时的weakSelf已经是null了, 如果我们做如下修改

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@ %@", strongSelf, name);
        });
    }];
    self.callBack(@"come on");
}

输出结果如下

2017-12-23 11:57:05.182026+0800 循环引用问题[5709:215351] <TestViewController: 0x7ff217725e50> come on
2017-12-23 11:57:05.182414+0800 循环引用问题[5709:214769] <TestViewController: 0x7ff217725e50> dealloc

__strong可以使block对self进行强制持有, 使他的retainCount+1, 使self不能dealloc, 而strongSelf是个局部变量, 当block结束的时候就会自动释放掉, 所以此时的self的self的retainCount-1, 然后可以释放掉self.

- (void)viewDidLoad {
    [super viewDidLoad];
    __weak typeof(self) weakSelf = self;
    [self setCallBack:^(NSString *name) {
        NSLog(@"strong之前:%lu", CFGetRetainCount((__bridge CFTypeRef)(((NSObject *)weakSelf))));
        __strong typeof(weakSelf) strongSelf = weakSelf;
        NSLog(@"strong之后:%lu", CFGetRetainCount((__bridge CFTypeRef)(((NSObject *)weakSelf))));
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"%@ %@", strongSelf, name);
        });
    }];
    self.callBack(@"come on");
}

输出结果是

2017-12-23 12:01:57.725400+0800 循环引用问题[5782:221024] strong之前:10
2017-12-23 12:01:57.725636+0800 循环引用问题[5782:221024] strong之后:11
2017-12-23 12:02:02.729803+0800 循环引用问题[5782:221561] <TestViewController: 0x7f8bc6f04230> come on
2017-12-23 12:02:02.730176+0800 循环引用问题[5782:221024] <TestViewController: 0x7f8bc6f04230> dealloc

可以看到strong之后的retainCount+1了.

源码地址
https://github.com/autmaple/RetainCycleProblem

相关文章

网友评论

      本文标题:__weak和__strong的使用

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