造成循环引用的简单理解是:Block的拥有者在Block作用域内部又引用了自己,因此导致了Block的拥有者永远无法释放内存,就出现了循环引用的内存泄漏
示例代码
@interface ObjTest () { NSInteger testValue; } @property (copy, nonatomic) void (^block)(); @end @implement ObjTest - (void)function { /* //这里会循环引用 self.block = ^() { self.testValue = 100; }; */ __weak ObjTest* weakSelf = self;//使用弱引用,解决循环引用问题 self.block = ^() { weakSelf.testValue = 100; }; } @end
再看下面的例子
#import "networkTool.h" @implementation networkTool //定一个block的网络请求 -(void)loadData:(void (^)(NSString * _Nonnull))finishedBlock{ //执行网络请求 //... //完成回调返回 finishedBlock(@"jsonData"); } @end
@interface ViewController () @property (nonatomic,strong) networkTool *tool; @end @implementation ViewController - (IBAction)button1Action:(id)sender { self.tool=[networkTool new]; [self.tool loadData:^(NSString * _Nonnull jsonData) { NSLog(@"接收到请求数据:%@",jsonData); self.view.backgroundColor=[UIColor redColor];//此处没有循环引用 }]; } - (void)dealloc { NSLog(@"ViewController -- dealloc"); } @end
他们之间的引用关系 Block引用ViewController,ViewController引用networkTool,但是networkTool没有引用Block,如下图
下面这样会发生循环引用
@interface networkTool() @property (nonatomic,copy) void(^finishedBlock2)(NSString*); @end @implementation networkTool //定一个block的网络请求 -(void)loadData:(void (^)(NSString * _Nonnull))finishedBlock{ self.finishedBlock2 = finishedBlock;//小心block循环引用 //执行网络请求 //... //完成回调返回 finishedBlock(@"jsonData"); } @end //===============ViewController================ @interface ViewController () @property (nonatomic,strong) networkTool *tool; @end @implementation ViewController - (IBAction)button1Action:(id)sender { self.tool=[networkTool new]; //block引起循环引用问题 [self.tool loadData:^(NSString * _Nonnull jsonData) { NSLog(@"接收到请求数据:%@",jsonData); self.view.backgroundColor=[UIColor redColor]; }]; } - (void)dealloc { NSLog(@"ViewController -- dealloc"); } @end
上面他们之间的引用关系 Block引用ViewController,ViewController引用networkTool,而且networkTool引用Block
解决方法:破坏这个闭合的环,如下
__weak typeof(self) weakSelf=self; [self.tool loadData:^(NSString * _Nonnull jsonData) { NSLog(@"接收到请求数据:%@",jsonData); weakSelf.view.backgroundColor=[UIColor redColor]; }];