iOS 之 block的 Weak-Strong-Dance

先看看我看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 了,这样才能确保万无一失。

你可能感兴趣的:(iOS 之 block的 Weak-Strong-Dance)