block循环引用的问题:

在ARC模式下
执行下面语句:

1. - (IBAction)onTest:(id)sender  
2. {  
3.     BlockDemo *demo = [[BlockDemo alloc]init];  
4.     [demo setExecuteFinished:^{  
5.         if (demo.resultCode == 200) {  
6.             NSLog(@"call back ok.");  
7.         }  
8.     }];  
9.       
10.     [demo executeTest];  
11.        
12. }  

执行输出结果:

1. 2015-07-24 19:20:33.997 blockDemo[25215:60b] Object Constructor!  
2. 2015-07-24 19:20:39.000 blockDemo[25215:60b] call back ok.  
一样会被引入循环。

相信看到这里的人,大多都要喷了,这哪一个不知道呀,还知道怎么解决呢,非ARC中加了个__block,固然的在ARC中加一个__weak就搞定了。嗯,确实是这样,但别急,接着往下看,绝对有收获。在这里先本身默认想一下,你是如何加这个__weak的。


对于第一个问是点block 的循环引用(retain cycle)到这里暂告结束。下面讲第二点。由于block告警在非ARC 中暂未发现因写法引入(若是你知道,麻烦告诉我怎么弄产生告警,我好研究一下。)
下面讲在ARC模式下去除因写法产生的告警时须要注意的问题。
像上面的写法其实在ARC中会产生(Capturing 'demo' strongly in this block is likely to lead to a retain cycle)告警。以下图:


在ARC中,编译器智能化了,直接提示这样写会产生循环引用。所以不少爱去除告警的朋友就会想法去掉,好,咱再来看去掉时需注意的问题。
状况一:

1. - (IBAction)onTest:(id)sender  
2. {  
3.     __weak BlockDemo *demo = [[BlockDemo alloc]init];  
4.     [demo setExecuteFinished:^{  
5.         if (demo.resultCode == 200) {  
6.             NSLog(@"call back ok.");  
7.         }  
8.     }];  
9.     [demo executeTest];  
10. }  
直接在前面加一个__weak,但这样真的没有告警了吗?若是有,哪么恭喜欢你,说明编译器还帮你大忙。见下图





这时还会告警,说这是一个WEAK变量,就立刻会被release。所以就不会执行block中的内容。你们能够运行一下看
输出结果为:
1. 2014-07-24 19:38:02.453 blockDemo[25305:60b] Object Constructor!  
2. 2014-07-24 19:38:02.454 blockDemo[25305:60b] Object Destoryed!  
很显然,立刻被release了,因此block 中的代码根本就不执行。

谢天谢地,幸亏编译器提早告诉了咱们有这个隐性危险。相信你们为解决告警,又会获得一个比较圆满的解决方案,见下:
1. - (IBAction)onTest:(id)sender  
2. {  
3.     BlockDemo *demo = [[BlockDemo alloc]init];  
4.       
5.     __weak typeof(BlockDemo) *weakDemo = demo;  
6.       
7.     [demo setExecuteFinished:^{  
8.         if (weakDemo.resultCode == 200) {  
9.             NSLog(@"call back ok.");  
10.         }  
11.     }];  
12.     [demo executeTest];  
13. }  

这样写,即去除了告警又保证了block的运行。这才是咱们最终想要的结果。
输出为:

1. 2014-07-24 19:40:33.204 blockDemo[25328:60b] Object Constructor!  
2. 2014-07-24 19:40:38.206 blockDemo[25328:60b] call back ok.  
3. 2014-07-24 19:40:38.207 blockDemo[25328:60b] Object Destoryed!  

但你们别得意。有提示,相信你们都能处理,并获得个好的解决方法。哪么下面大来再来看一下这个写法,让你真心甘拜下风。。。。。

1. - (IBAction)onTest:(id)sender  
2. {  
3.     __weak BlockDemo *demo = [BlockDemo blockdemo]; //这里才是重点,前面是[[BlockDemo alloc]init];会有告警。  
4.       
5.     [demo setExecuteFinished:^{  
6.         if (demo.resultCode == 200) {  
7.             NSLog(@"call back ok.");  
8.         }  
9.     }];  
10.     [demo executeTest];  
11. }  


其实只是把init放到了类方法中进行书写而已,但会有什么不一样。

1. + (BlockDemo *)blockdemo  
2. {  
3.     return OBJC_AUTORELEASE([[BlockDemo alloc]init]);  
4. }  
不一样点见下图:真心看不到做何告警,是否是。但这存在什么风险,风险就是运行的时候,block根本就没有run。由于对象早就释放了。


直接输出:

1. 2015-07-24 19:47:53.033 blockDemo[25395:60b] Object Constructor!  
2. 2015-07-24 19:47:53.035 blockDemo[25395:60b] Object Destoryed!  

因 此,写这个主要用来告戒一些喜欢用BLOCK但又想固然的朋友,有一些朋友喜欢去除告警,但只是盲目的加上__weak 或__block关键语,每每可能存在一些重大的安全隐患。就像演示中block根本不走。若是到了发布时,为了去告警而这样简单的处理了,并无进行测 试就打包。哪么将死得很惨。。。。。


好,到了尾声,来讲说为何朋友问我block会不会引行死循环,我说不会的理由。
见码:

1. - (IBAction)onTest:(id)sender  
2. {  
3.     BlockDemo *demo = [BlockDemo blockdemo];//[[BlockDemo alloc]init];  
4.       
5.     [demo setExecuteFinishedParam:^(BlockDemo * ademo) {  
6.         if (ademo.resultCode == 200) {  
7.             NSLog(@"call back ok.");  
8.         }  
9.     }];  
10.       
11.     [demo executeTest];  
12. }  

不论是在外面init,仍是在里面,且没有加__block 及__weak。为何,由于我我的经常在使用本身写的block时,若是是回调,比较喜欢把自身看成参数传到block中。这样期实是编译器给咱们作了弱引用。所以不会产生循环引用。

由 于我一直都这样写block,因此朋友一问起,我就说不会循环引用了,由于压根他碰到的就是前面讲述的哪一种访问方式,而我回答的是个人这种使用方式。正因 为口头描述,与实际回复真是差之千里。。。哈哈。为了验证我朋友的这个,我特地写了个这篇文章,但愿对你们有所帮助。最后,谢谢你们花时间阅读。


安全

相关文章
相关标签/搜索