美文网首页iOS Developer
iOS 之 block的 Weak-Strong-Dance

iOS 之 block的 Weak-Strong-Dance

作者: charlotte2018 | 来源:发表于2017-08-05 20:29 被阅读274次

    先看看我看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

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