在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,因此朋友一問起,我就說不會循環引用了,由於壓根他碰到的就是前面講述的哪一種訪問方式,而我回答的是個人這種使用方式。正因 爲口頭描述,與實際回覆真是差之千里。。。哈哈。爲了驗證我朋友的這個,我特地寫了個這篇文章,但願對你們有所幫助。最後,謝謝你們花時間閱讀。
安全