关于block嵌套定义导致的内存泄漏

block的使用极大方便了我们的开发,但是不正确的使用block时就会导致意想不到的问题。
[toc]

1. 单层block
dispatch_async(dispatch_get_main_queue(), ^{
                [self stopCaptureAfer] ;
            });

如上代码block会捕获self这是显而易见的;

2. 嵌套的block
__weak typeof(self) weakSelf = self;
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    [self.KVOControllerNonRetaining observe:captureDevice keyPath:@"rampingVideoZoom" options:0 block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) {
        __typeof(weakSelf) strongSelf = weakSelf;
        strongSelf.rampingVideoZoom = 1;
        if (YES) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self stopCaptureAfer] ;
            });
        }
    }];

上述代码呢?self的捕获过程又是怎样的呢?

实际的结果是循环引用了;

3. 为什么

分析过程:

self.KVOControllerNonRetaining是使用了FBKVOController,它会持有最后的^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) 的block参数
这个block里虽然使用了weakSelf,但是由于这个block里又定义了一个dispatch_async的block,该block里明显会捕获self,从而导致嵌套的上一层block也会捕获self;
从而最终导致了循环引用;

首先明白weak的意义是什么,ARC下,weak是告诉编译器不需要去捕获该变量,所以block就不会持有/捕获weak声明定义的变量,而对于非weak定义的NS对象block会自动的捕获一次。因此block会自动捕获所引用的变量;

其次,嵌套定义的block,其所捕获的变量,必须在其定义的上下文中能找到,如果其定义的上下文中没有显示捕获这个待捕获的变量,则该上下文也会捕获一次该变量;所以嵌套定义的block里需要留意这一点;

4. 结论

要注意嵌套block里依旧不要显示使用self;而是继续使用原先的weak-strong-dance的模式即可;

猜你喜欢

转载自blog.csdn.net/weixin_33714884/article/details/87390982