最近在看Blocks Programming Topics中Blocks有如下的这段话:
When you copy a block, any references to other blocks from within that block are copied if necessary—an entire tree may be copied (from the top). If you have block variables and you reference a block from within the block, that block will be copied.
大致翻译如下:
当你复制一个block的时候,在这个block里的其他block任何引用也会被复制,如果有必要的话,一颗完整的树也许被复制(从顶部开始)。如果你有block变量并且你在这个block引用了另一个block,另一个block也会被复制。
测试对象:RXBlockBlockObject
@interface RXBlockBlockObject : NSObject
- (void)test;
@end
RXBlockBlockObject.m文件中:
@interface RXBlockBlockObject()
@property (nonatomic, copy) int(^block)(int);
@property (nonatomic, assign) int tmpValue;
@end
@implementation RXBlockBlockObject
- (void)test
{
[self _test_block_normal];
// [self _test_block_nested_retain_cycle];
// [self _test_block_nested];
}
- (void)dealloc
{
NSLog(@"RXBlockBlockObject dellloc");
}
@end
测试类中:
- (void)_test_block
{
RXBlockBlockObject *tmp = [RXBlockBlockObject new];
[tmp test];
// tmp 会被释放的
}
_test_block_normal method
- (void)_test_block_normal
{
self.tmpValue = 10;
self.block = ^(int m) {
return m + 4;
};
void (^block1)(void) = ^{
NSLog(@"%zd", self.block(5));
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block1);
}
持有关系如下描述:
self(viewController)持有了block,dispatch_after的一个全局管理器持有了block1,block1持有了self,没有出现循环引用。
输出如下:
9
RXBlockBlockObject dellloc
_test_block_nested_retain_cycle method
- (void)_test_block_nested_retain_cycle
{
self.tmpValue = 10;
// A(self)强引用了B(block),B强引用了C(block1),C强引用了A(self)了,导致循环引用
self.block = ^(int m) {
// inline block
void (^block1)(void) = ^{
// 不会提示warning,但是实际上已经出现了循环引用
NSLog(@"%zd", self.tmpValue + m);
// 会提示warning: Capturing 'self' strongly in this block is likely to load to a retain cycle
// 但是感觉这是无限递归调用了~~~~
// NSLog(@"%zd", self.block(10));
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block1);
return m + 4;
};
void (^block2)(void) = ^{
NSLog(@"%zd", self.block(5));
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block2);
}
持有关系如注释中的描述:
A(
self)强引用了B(block),B强引用了C(block1),C强引用了A(self)了,导致循环引用。
输出结果是:
9
15
不会调用dealloc,出现循环引用,内存泄漏了
_test_block_nested method 上一个的进化版本,解决循环引用
- (void)_test_block_nested
{
self.tmpValue = 10;
__weak __typeof(self) weakSelf = self;
self.block = ^(int m) {
// inline block
__strong __typeof(self) strongSelf = weakSelf;
void (^block1)(void) = ^{
NSLog(@"%zd", strongSelf.tmpValue + m);
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block1);
return m + 4;
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%zd", self.block(5));
});
}
使用__weak和__strong解决,block2延长了self的生命周期
输出结果:
9
15
RXBlockBlockObject dellloc










网友评论