跳出 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.
网友评论