iOS循環(huán)引用的幾種情況

你踩過的坑里盡是前人的腳印颂斜。---------前言

在開發(fā)過程中我們會遇到一些循環(huán)引用的問題惠拭,像循環(huán)引用Block是我們最常見的循環(huán)引用問題删性,但是有一些循環(huán)引用是很隱蔽的,稍有不慎就會導致內存泄漏油坝,比如GCD&NSNotification嫉戚。今天我們就踩在前人的腳印上來分析循環(huán)引用這個老生常談的話題。


循環(huán)引用的三種情況.png

一澈圈、Block

我們舉一個最簡單的例子:
[self.teacher requestData:^(NSData *data) {
    self.name = @"case";
}];

這種情況是最常見的循環(huán)引用導致的內存泄漏的情況彬檀,此時,self強引用了teacher瞬女,而teacher又強引用了一個Block窍帝,該Block回調時又強引用了self,從而導致了循環(huán)引用诽偷,self無法釋放坤学。
self->teacher->block->self

解決辦法

此時我們通過__weak弱引用self,在Block里面調用weakself從而打破循環(huán)报慕。

__weak typeof(self) weakSelf = self;
    [self.teacher requestData:^(NSData *data) {
        //__strong typeof(weakSelf) strongSelf = weakSelf; 
       strongSelf.name = @"case";
    }];

注意:我們在使用為什么要在Block里面添加__strong呢深浮?在什么情況下使用__strong呢?會造成什么影響呢眠冈?下面我們就根據(jù)具體的場景來分析:

場景1:block非異步執(zhí)行

在調用requestData:block時就已經(jīng)執(zhí)行飞苇,因為在同步情況下,self是不會在Block執(zhí)行時被釋放掉的了蜗顽,此時的strongself變量是可以省略的布卡。

場景2:block異步執(zhí)行
//此方法在A頁面,觸發(fā)之后立刻進入到B頁面雇盖。
self.block = ^{  
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
        [NSThread sleepForTimeInterval:5];  
        [weakSelf print];  
    });  
};
- (void)print  
{  
    NSLog(@"---->print");  
}  

在此種場景下忿等,Block內部的方法不會執(zhí)行,但是為什么呢刊懈?原因就是self在Block執(zhí)行完畢之前就釋放掉了这弧,Block實體釋放了娃闲,self就指向nil虚汛,weakSelf也會被置nil,這就相當于想一個nil發(fā)送消息皇帮。__strong它的主要作用就是應對異步執(zhí)行的Block卷哩。處理如下:

__weak typeof(self) weakSelf = self; 
self.block = ^{  
 __strong typeof(weakSelf) strongSelf = weakSelf;  
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
        [NSThread sleepForTimeInterval:5];  
        [strongSelf print];  
    });  
};
引申出的問題:

到這里肯定有同學有疑問了,再使用__strong不是又強引用了嗎属拾,這不又成了循環(huán)引用了将谊?實際上并非如此冷溶,__strong修飾的strongSelf是Block內部的一個局部變量,也就是說作用域僅在Block內部尊浓,一旦跳出作用域逞频,那么我們強制產(chǎn)生的臨時“循環(huán)引用”就會被打破,所以也就不會有循環(huán)引用的情況了栋齿。

二苗胀、GCD

GCD使用參數(shù)包含self,且Block中也包含self瓦堵,那么此時就要考慮循環(huán)引用的問題了:

@property (nonatomic,retain)  dispatch_queue_t operationsQueue;
//tips:在iOS6.0之前也就是MRC時代是使用assign基协。
__weak __typeof__(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^
{
__typeof__(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doSomethingElse];
} );

三、NSNotification

@property (nonatomic, strong) id observer; //持有注冊通知后返回的對象

__weak __typeof__(self) weakSelf = self;
 _observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
                                                               object:nil
                                                                queue:nil
                                                           usingBlock:^(NSNotification *note) {
     __typeof__(self) strongSelf = weakSelf;
     [strongSelf dismissModalViewControllerAnimated:YES];
 }];

self --> _observer --> block --> self 顯然這也是一個循環(huán)引用菇用,所以也要進行弱引用處理澜驮。
tips: Facebook 開源的一個檢測循環(huán)引用工具 FBRetainCycleDetector

四惋鸥、不會造成循環(huán)引用的情況

1杂穷、UIView動畫

[UIView animateWithDuration:duration animations:^{ [self.superview layoutIfNeeded]; }]; 

2、NSNotification

[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification" 
                                                 object:nil 
                          queue:[NSOperationQueue mainQueue]
                                             usingBlock:^(NSNotification * notification) {
                                                   self.someProperty = xyz; }]; 

3揩慕、GCD

[[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.someProperty = xyz; }]; 

以上三種情況都是單向“強引用”亭畜,只是Block持有self,但self并沒有持有block迎卤,所以不用考慮“循環(huán)引用”的問題拴鸵。

參考資料如下
Block循環(huán)引用分析:
https://blog.csdn.net/lizitao/article/details/54845974
http://www.cocoachina.com/ios/20170122/18601.html
NSNotification循環(huán)引用分析:
http://www.reibang.com/p/0209668d33db

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜗搔,隨后出現(xiàn)的幾起案子劲藐,更是在濱河造成了極大的恐慌,老刑警劉巖樟凄,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件聘芜,死亡現(xiàn)場離奇詭異,居然都是意外死亡缝龄,警方通過查閱死者的電腦和手機汰现,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叔壤,“玉大人瞎饲,你說我怎么就攤上這事×痘妫” “怎么了嗅战?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長俺亮。 經(jīng)常有香客問我驮捍,道長疟呐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任东且,我火速辦了婚禮启具,結果婚禮上,老公的妹妹穿的比我還像新娘珊泳。我一直安慰自己富纸,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布旨椒。 她就那樣靜靜地躺著晓褪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪综慎。 梳的紋絲不亂的頭發(fā)上涣仿,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音示惊,去河邊找鬼好港。 笑死,一個胖子當著我的面吹牛米罚,可吹牛的內容都是我干的钧汹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼录择,長吁一口氣:“原來是場噩夢啊……” “哼拔莱!你這毒婦竟也來了?” 一聲冷哼從身側響起隘竭,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤塘秦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后动看,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尊剔,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年菱皆,在試婚紗的時候發(fā)現(xiàn)自己被綠了须误。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡仇轻,死狀恐怖京痢,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情拯田,我是刑警寧澤历造,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布甩十,位于F島的核電站船庇,受9級特大地震影響吭产,放射性物質發(fā)生泄漏。R本人自食惡果不足惜鸭轮,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一臣淤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窃爷,春花似錦邑蒋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至逮京,卻和暖如春卿堂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背懒棉。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工草描, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人策严。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓穗慕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親妻导。 傳聞我的和親對象是個殘疾皇子逛绵,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容