關于 Block 導致的循環(huán)引用

,經常說在 block 里面很容易導致循環(huán)引用(retain cycle),可是為什么會導致循環(huán)引用,卻不是特別理解,最近研究了,也算是做一個總結.

常見的循環(huán)引用

看看這個類
代碼1

@interface TestClass : NSObject
@property (nonatomic,copy)void (^block)();
-(void)test;
@end

有一個屬性, block,一個方法 test
來看看類實現(xiàn)
代碼2

@implementation TestClass
-(void)dealloc{
    NSLog(@"dealloc");
}
-(void)test{
    self.block=^{
        NSLog(@"%@",self);
    };
}
@end

可以看到, test方法中有一個明顯的在 self.block中調用self的過程.來看看會不會導致循環(huán)引用.
接下來,隨便在其他類中來調用一下這個類
代碼3

TestClass* test=[TestClass new];
[test test];

運行試試

2016-01-29 10:55:14.035 test[16318:1121947] <TestClass: 0x7fd3eb52b250>**

沒有輸出 "dealloc",說明 test對象沒有被釋放,怎么辦?
很簡單就會想到使用弱引用,
來看看使用弱引用的代碼
代碼4

-(void)test{
    __weak typeof(self) weakself=self;
    self.block=^{
        NSLog(@"%@",weakself);
    };
    self.block();
}

輸出

2016-01-29 10:58:01.899 test[16360:1124161] <TestClass: 0x7f9d61c4c240>
2016-01-29 10:58:01.899 test[16360:1124161] dealloc

可以看到, self 被成功釋放了,沒有被循環(huán)引用.

為什么?

首先, block 會自動捕獲block 內部使用的變量,并對其強引用.具體過程可以參考 Objective-C高級編程.
在本例中代碼2, block 內部有 self ,因為self 本身是一個強引用,所以block 會再給 self 加上一個強引用.
block 本身是self 的一個屬性,self也強持有block.
這就出現(xiàn)一個問題, self強持有block,block 強持有self,當self想要釋放的時候,要看一下有沒有自己強引用,而 block剛好強持有自己,所以,暫時沒辦法釋放.block 想要釋放的時候,卻發(fā)現(xiàn) self強持有自己,所以也得不到釋放,相互糾纏.

而為何代碼4 又可以呢?
代碼4中, block 內部有一個 weakself,weakself 本身是一個弱引用,由于對弱引用無法強持有,所以, block 并沒有強持有self,當 self 想要釋放的時候,已經沒有其他強引用了,就可以釋放.self被釋放,就沒有變量強持有block,block也會釋放.這樣,循環(huán)引用就不存在了.

引申

既然只要不相互持有就可以,那么我們手動的去掉強引用還會不會發(fā)生循環(huán)引用呢?
看看這個代碼.
代碼5

-(void)test{
    self.block=^{
        NSLog(@"%@",self);
    };
    self.block();
    self.block=nil;
}

這里在執(zhí)行完畢后,手動去掉了 block 的強引用.由于打破了相互引用,自然也不會有循環(huán)引用.
看看輸出

2016-01-29 11:25:25.238 test[16439:1133368] <TestClass: 0x7fb381511b80>
2016-01-29 11:25:25.239 test[16439:1133368] dealloc

果然如此,不過這種方法畢竟很不安全,要是block是需要在一段時間后調用的,如果你馬上就釋放了,那么 block 中代碼就不能執(zhí)行.又或者,如果你忘記手動釋放,也會造成很大麻煩,相對之下,使用 weakself就好多了.
另外,在使用weakself的時候,可以和strongself一起使用,可以參考我的文章為什么要用 strongSelf

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市奴艾,隨后出現(xiàn)的幾起案子蕴潦,更是在濱河造成了極大的恐慌,老刑警劉巖潭苞,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件此疹,死亡現(xiàn)場離奇詭異,居然都是意外死亡湖笨,警方通過查閱死者的電腦和手機蹦骑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門眠菇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人放闺,你說我怎么就攤上這事缕坎∶仗荆” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵艳悔,是天一觀的道長。 經常有香客問我猜年,道長疾忍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任杨幼,我火速辦了婚禮差购,結果婚禮上汉嗽,老公的妹妹穿的比我還像新娘。我一直安慰自己饼暑,他們只是感情好,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布迈着。 她就那樣靜靜地躺著裕菠,像睡著了一般闭专。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上画髓,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天平委,我揣著相機與錄音,去河邊找鬼肉微。 笑死,一個胖子當著我的面吹牛勿负,可吹牛的內容都是我干的劳曹。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼锭硼,長吁一口氣:“原來是場噩夢啊……” “哼库菲!你這毒婦竟也來了?” 一聲冷哼從身側響起鳖擒,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤蒋荚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后馆蠕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡播赁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年容为,在試婚紗的時候發(fā)現(xiàn)自己被綠了坎背。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡得滤,死狀恐怖懂更,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情沮协,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站命黔,受9級特大地震影響,放射性物質發(fā)生泄漏蘑辑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一洋魂、第九天 我趴在偏房一處隱蔽的房頂上張望副砍。 院中可真熱鬧庄岖,春花似錦、人聲如沸隅忿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽链峭。三九已至,卻和暖如春纷责,著一層夾襖步出監(jiān)牢的瞬間撼短,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工喂柒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灾杰。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像麦备,于是被迫代替她去往敵國和親昭娩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內容