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的模式即可;