先看看我看sdwebimage的时候,作者写block的时候对Weak-Strong-Dance的应用吧。
// 在block外部有这么一段代码
__block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new];
__weak SDWebImageCombinedOperation *weakOperation = operation;
// 在block里有这么一段代码
__strong __typeof(weakOperation) strongOperation = weakOperation;
if (strongOperation) {
[strongOperation 做事情];
}
防止循环引用
众所周知,Block强引用self,self强引用block的时候会发生循环引用。我们一般都是给个弱指针weakSelf。代码如下
MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyViewController = myController;
myController.completionHandler = ^(NSInteger result) {
[weakMyViewController dismissViewControllerAnimated:YES completion:nil];
};
但是绝大多数人对于 Block 的使用就到此为止了……如果我要在 Block 里 removeObserver 你猜会发生什么?
崩溃!因为 weakMyViewController 被弱引用,在 ARC 的环境下(尤其还有可能伴随着多线程)随时可能被释放,这样就会导致因为解除 KVO 而引起 Crash。
虽然是小概率的事件,但是对于一个严格要求自己的程序员,再小概率的 Crash 触发也是不能放过的!
这时候你可能会想,我加一个if判断,看一下 weakMyViewController 是否为 nil 不就行了,比如这样
MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyViewController = myController;
myController.completionHandler = ^(NSInteger result) {
if (weakMyViewController != nil) {
//在这里removeObserver
}
[weakMyViewController dismissViewControllerAnimated:YES completion:nil];
};
不可以!考虑到多线程执行,也许在判断的时候,self 还没释放,但是执行 self 里面的代码时,就刚好释放了
weak-strong dance
这时候我们进入到 AFNetworking 这个框架里,看看大牛是如何解决这个问题的~
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
strongSelf.networkReachabilityStatus = status;
if (strongSelf.networkReachabilityStatusBlock) {
strongSelf.networkReachabilityStatusBlock(status);
}
};
strong typeof(weakSelf)strongSelf = weakSelf;就是解决这个问题的关键
__weak __typeof(self)weakSelf = self;先将强引用的对象转为弱引用指针,防止了 Block 和对象之间的循环引用。
strong typeof(weakSelf)strongSelf = weakSelf;再在 Block 的第一句代码出将 weakSelf 的弱引用转换成 strongSelf 这样的强引用指针,防止了多线程和 ARC 环境下弱引用随时被释放的问题。
因为strongSelf是在block里创建的,当block执行完毕,出了block的大括号,strongSelf就销毁了。所以不会一直持有self。
更安全的方法
苹果官方文档的解释,在里面我们看到了这样一串代码:
MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
MyViewController *strongMyController = weakMyController;
if (strongMyController) {
// ...
[strongMyController dismissViewControllerAnimated:YES completion:nil];
// ...
}
else {
// Probably nothing...
}
};
if (strongMyController) 是这段代码的亮点。之所以在Block的代码执行之前加上这样一个判断,就是为了防止在把 weakSelf 转换成 strongSelf 之前 weakSelf 就已经为 nil 了,这样才能确保万无一失。