前言网络
在咱们开发的过程当中,block运用的很是普遍,为了不写过多的delegate或者是通知等,项目中会运用大量的block回调,虽然如今大部分的工程都是采用ARC,可是在ARC上面使用block更为复杂,在ARC机制下block自动的被copy到堆上(若是是在stack,或者是全局区是不会形成循环引用的),更具体的怎么个复杂状况,我在这里就不阐述了,你们能够去参考网络上的文章,已经写得很全面了;你们能够去参考学习他们的文章。函数
(一)本文主要描述在使用block回调过程当中一个比较容易产生循环引用的场景,即在block中引用了对象自己的成员变量或者说属性;如下是我准备的一些方法,学习
#import "SuperObject.h" #import <UIKit/UIKit.h> @class SonObject; typedef void(^CustomerBlock)(); typedef void(^CustomerBlockWithPara)(SonObject *son); @interface SonObject : SuperObject @property (nonatomic,copy) CustomerBlock blockTest; @property (nonatomic,copy) NSString *age; - (void)demo:(CustomerBlock)block; - (void)demoPara:(CustomerBlockWithPara)paraBlock; - (void)excuteBlock; @end #import "SonObject.h" @interface SonObject () { CustomerBlock customerBlock; CustomerBlockWithPara customerBlockPara; } @end @implementation SonObject //+ (void)initialize //{ // NSLog(@"SonObject 执行initialize %@",[self class]); //} // //- (SonObject *)init //{ // NSLog(@"SonObject 执行init %@",[self class]); // return [super init]; //} - (void)demo:(CustomerBlock)block { customerBlock = block; // self.blockTest = block; // //NSLog(@"block address -- %@",self.blockTest); // NSLog(@"====demo=== %@",block); //self.blockTest(); } - (void)excuteBlock { self.age = @"20"; if (customerBlock) { customerBlock(); } if (customerBlockPara) { customerBlockPara(self); } } - (void)demoPara:(CustomerBlockWithPara)paraBlock { customerBlockPara = paraBlock; } - (void)dealloc { NSLog(@"dealloc"); } @end
(二)制造一个循环引用的例子,使用了SonObject中的age属性。this
//例子一 SonObject *son = [[SonObject alloc] init]; [son demo:^{ if ([son.age isEqualToString:@"20"]) { NSLog(@"====%@",@"right"); } }]; [son excuteBlock]; //例子二 son.blockTest = ^{ son.age = @"30"; };
例子一:son引用了customerBlock(是SonObject中的全局成员变量),而后在customerBlock中又引用了SonObject的age属性,所以形成了循环引用;(值得注意的是,个人编译器中居然不提示Capturing 'demo' strongly in this block is likely to lead to a retain cycle),这让我很费解;最后SonObject中的dealloc函数并无执行,即son对象并无被释放掉。atom
例子二:比较明显,son引用了blockTest属性,blockTest属性又引用了son的age属性;(这回编译器提示了警告Capturing 'demo' strongly in this block is likely to lead to a retain cycle),why?为何例子一的没有提示?我也在求解。code
(三)消除以上的循环引用,让son这个对象得以释放掉;对象
- (void)testBlock { //方法一,建立一个指向son的弱引用对象 SonObject *son = [[SonObject alloc] init]; __weak typeof(son) weakSelf = son; //NSLog(@"test address -- %@",_sonObject); [son demo:^{ if ([weakSelf.age isEqualToString:@"20"]) { NSLog(@"====%@",@"right"); } }]; [son excuteBlock]; // //例子一 // SonObject *son = [[SonObject alloc] init]; // // [son demo:^{ // // if ([son.age isEqualToString:@"20"]) { // // NSLog(@"====%@",@"right"); // } // }]; // // [son excuteBlock]; // // //例子二 // son.blockTest = ^{ // // son.age = @"30"; // }; //方法二,执行回调函数时,将自身(self)当作参数回传到block,这样就像是编译器给咱们作了弱引用操做; son = [[SonObject alloc] init]; [son demoPara:^(SonObject *son) { if ([son.age isEqualToString:@"20"]) { NSLog(@"====%@",@"right"); } }]; [son excuteBlock]; }
执行testBlock后,你会发现dealloc被成功的执行(2次),即每一次建立的对象都被成功释放掉了。内存
(四)总结开发
以上写的内容是个人我的的理解,也许有些地方理解错误了,也但愿你们多多的指出来,你们互相的学习,block形成的循环引用太常见,避免它,以防内存泄漏。编译器