MacDev 板


LINE

Blog版 http://popcornylu.blogspot.com/2011/08/objective-c-block-part-3.html 前面講了簡單的block用法跟block variable, 但是block難的地方應該就是記憶體管理的部份, 如果你不是很瞭解block內部的記憶體管理, 很容易一個不小心就導致circular reference而導致memory leakage.. 前篇有提到,我們可以把block當作參數傳給function或是message, 但是傳進去後,有可能這個function會想把你的block pointer留下來 最常見的就是做event handling的例子, 我們把一個事件觸發的block當作參數丟進來, 但是是件觸發可能是數秒之後的事情, 而此時註event handler的function/message已經return了, 那此block所reference的local變數可能已經invalid了, 這時候block要怎麼處理這樣的情形呢? 首先,在block的定義中,此block還停留在call stack之中, 也就是他的生命週期會隨著定義此block的function return之後,其生命週期就會結束 除非我們呼叫block_copy或是[myblock copy] 此時block才會從stack變到heap中。 之後我們才可以把參數傳過來的block指給instance variable或是global variable, 而block中所用到的物件在此同時reference count也會+1。 但reference count +1這件事情卻在每一種case不一樣 因為block內部可以使用環境中看的到 local, block, instance, local static, global variable 那copy這個動作會發生什麼事情呢? 我們先寫一個範例code //MyBlockTest.h #import <Foundation/Foundation.h> typedef void (^myBlockTest_type)(void); @interface MyBlockTest : NSObject { NSObject* instanceRef; myBlockTest_type myBlock; } - (void) test; @end //MyBlockTest.m #import "MyBlockTest.h" @implementation MyBlockTest static NSObject* globalRef; +(void) initialize { globalRef = [NSObject new]; } - (id)init { self = [super init]; if(self) { instanceRef = [NSObject new]; } return self; } - (void) test { // Local variable NSObject* localRef = [NSObject new]; // Block variable __block NSObject* blockRef = [NSObject new]; // Local static variable static NSObject* localStaticRef; if(!localStaticRef) localStaticRef = [NSObject new]; // create a block myBlockTest_type aBlock = ^{ NSLog(@"%@", localRef); NSLog(@"%@", blockRef); NSLog(@"%@", instanceRef); NSLog(@"%@", globalRef); NSLog(@"%@", localStaticRef); }; //copy the block myBlock = [aBlock copy]; NSLog(@"%d", [localRef retainCount]); NSLog(@"%d", [blockRef retainCount]); NSLog(@"%d", [instanceRef retainCount]); NSLog(@"%d", [globalRef retainCount]); NSLog(@"%d", [localStaticRef retainCount]); [localRef release]; } @end 大家可以先想想看,當呼叫test的時候,會印出什麼樣的結果? 正確的答案是 2 1 1 1 1 不知道你答對了沒? 第一個localRef應該最能夠理解,基本上就是+1,這個就是這樣設計。 第二個blockRef,由前面一張對block variable的解釋, 我們可以知道block variable是一個closure用一份。 因此此block variable並沒有額外的retain的動作。 所以被block variable指到的物件也不會有reference count +1的情況。 第三個instanceRef為什麼沒有+1呢? 事實上這個問題也是挺有陷阱題的味道。 對block來講,他看到的是self這個變數,而非instanceRef。 所以ref. count +1的不是instanceRef而是self。 如果在block copy的前後各把self的ref count印出來你就可以佐證這個事實了。 第四個globalRef跟第五個localStaticRef本質上很像,所以兩個可以一起討論。 由於這兩個變數在runtime中的位置是固定而且唯一的, 所以基本上在block內用上面兩個變數跟block沒有什麼兩樣。 因此block copy並不會也不需要增加ref. count的數目。 瞭解之後,那什麼時候可能會出現circular reference呢? 其實跟我們之前聊到的 http://popcornylu.blogspot.com/2011/07/delegate.html (ios delegate你必須知道的事情) 所說的內容很像 只是這次主角從delegate換成block。 試想,如果有3個view controller,分別是VC1, VC2, VC3 如果VC1產生並retain VC2 VC2也產生VC3 而且VC2可能跟VC3註冊了一個event handler並且參數是用一個block。 在這個block中可能長這樣。 [vc3 setOnClose:^{ [self dismissModalViewControllerAnimated:YES]; }]; 那這樣會發生什麼事情呢? 答案是當VC1 release VC2的時候, VC2因為自己有參照VC3,所以VC3的retain count還是1 VC3因為他的instance variable有retain這個block 而這個block因為用到block中的self 這個self就是VC2, 那這樣可糟了個糕,circular的悲劇就產生了。 目前官方文件告訴我們要這樣做 __block VC2* tempVC2 = self; [vc3 setOnClose:^{ [tempVC2 dismissModalViewControllerAnimated:YES]; }]; 我們透過block variable不會retain的特性, 來把self丟給tempVC2, 如此在block在被copy的時候不會增加retain count。 我只能說太不friendly了, 不過目前好像也只有這樣解,而且到了ARC之後這個問題還是存在。 所以大家一定要改清楚block的memory management, 才不會不知道為什麼,reference count永遠不會歸零的狀況。 --



※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 114.32.239.120 ※ 編輯: popcorny 來自: 114.32.239.120 (08/30 23:18)
1F:推 aecho:推這篇 08/31 06:36







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:e-shopping站內搜尋

TOP