跳出 Block 的坑 --- weak-strong danc

2016-10-28  本文已影响32人  47号同学

跳出 Block 的坑

使用过 Block 的开发者都有一个意识就是,要防止 retain cycel(循环引用)。如何防止 retain cycle 也有很多文章描述过了,但是你的做法真的是安全的吗?下面我们来探究一下 weak-strong dance.

下面来看一下代码:

- (void)blockRetainCycleProblem {
    self.block = ^{
        NSLog(@"%@", @[self]);
    };
}

上面一段代码很明显就是出现了 retain cycel,于是你的解决办法就是如下了:

- (void)blockRetainCycleProblemAnswer0 {
    __weak typeof(self) weakSelf;
    self.block = ^{
        NSLog(@"%@", @[weakSelf]);
    };
}

上面的解决方案真的安全吗?

如果在 block 执行之前,self 被主线程释放掉了,而 weakself 却是对 self 的弱引用,所以根据 ARC 的规则,weakself 会被赋值为 nil(不明白为何为 nil ,可以点击这里)。当 weakself 为 nil,block 中执行的代码就会导致程序 crash。

于是,又出现下面这种解决方式:

- (void)blockRetainCycleProblemAnswer1 {
    __weak typeof(self) weakSelf;
    self.block = ^{
        __strong  typeof(weakSelf) strongSelf = weakSelf;
        NSLog(@"%@", @[strongSelf]);
    };
}

为什么上面这种做法可以防止程序 crash 呢?

因为 strongSelf 强引用了一次 self ,这时候 self 的 retainCount 为2,即是 self 超出了作用域,引用它的还有 strongSelf 对象,其 retainCount 依然是1,对象还未被释放,依然存在。

更安全的解决方式如下:

- (void)blockRetainCycleProblemAnswer2 {
    __weak typeof(self) weakSelf;
    self.block = ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        if (strongSelf) {
            NSLog(@"%@", @[strongSelf]);
        }
    };
}

防止 strongSelf 被释放,而执行相关操作,导致程序 crash.

上一篇下一篇

猜你喜欢

热点阅读