談?wù)凚lock

前言

??最近寫代碼時(shí)用到了很多block适秩,使用不當(dāng)就很容易因?yàn)檠h(huán)引用而造成內(nèi)存泄漏陆蟆。所以在這里簡單分析下什么是block以及block循環(huán)引用形成原因以及處理辦法浩嫌,如果有什么說錯的地方钠糊,請大神指出垫言,本文只是想起到一個拋磚迎玉的作用。
??有人可能會問瞻讽,用什么block啊鸳吸,代理不好嗎,又不會出錯速勇。我在這里要鄭重告訴你們晌砾,為啥用block,裝逼胺炒拧养匈!裝逼昂哂隆!裝逼芭缓酢;!(重要的事情說三遍)

什么是循環(huán)引用

??循環(huán)引用簡單的說就是兩個對象互相持有對方,所以當(dāng)這兩個對象都不會被釋放猬仁,造成內(nèi)存泄漏帝璧。

舉個??:
對象a創(chuàng)建并引用到了對象b.
對象b創(chuàng)建并引用到了對象c.
對象c創(chuàng)建并引用到了對象b.

??這時(shí)候b和c的引用計(jì)數(shù)分別是2和1。當(dāng)a不再使用b湿刽,調(diào)用release釋放對b的所有權(quán)的烁,因?yàn)閏還引用了b,所以b的引用計(jì)數(shù)為1诈闺,b不會被釋放渴庆。b不釋放,c的引用計(jì)數(shù)就是1买雾,c也不會被釋放。從此杨帽,b和c永遠(yuǎn)留在內(nèi)存中漓穿,造成內(nèi)存浪費(fèi)。

為什么block會造成循環(huán)引用

??我們使用的block其實(shí)是配置在棧上注盈, block為了保證代碼塊內(nèi)部對象不被提前釋放晃危,block 會唄復(fù)制到堆上,這樣是我們在寫 block 時(shí)他的屬性是copy老客。當(dāng)block被復(fù)制到堆上之后僚饭,block內(nèi)部對的象會被block所持有。所以當(dāng)block內(nèi)部對象又持有 block 時(shí)胧砰,就會造成循環(huán)應(yīng)用鳍鸵。

常見誤區(qū)

1.所有block都會造成循環(huán)引用

??其實(shí)并不是所有的block都會循造成環(huán)引用,比如UIView動畫block尉间、Masonry添加約束block偿乖、AFN網(wǎng)絡(luò)請求回調(diào)block等。
??UIView動畫block不會造成循環(huán)引用是因?yàn)檫@是類方法哲嘲,對象不可能強(qiáng)引用一個類贪薪,所以不會造成循環(huán)引用。
??Masonry約束block是局部變量眠副,block并沒有持有self画切,超出作用域后,就會被銷毀囱怕,所以也不會造成循環(huán)引用霍弹。

  • Masonry內(nèi)部代碼
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    constraintMaker.updateExisting = YES;
    block(constraintMaker);
    return [constraintMaker install];
}

- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    constraintMaker.removeExisting = YES;
    block(constraintMaker);
    return [constraintMaker install];
}

??AFN請求回調(diào)block不會造成循環(huán)引用是因?yàn)槟銈魅氲?code>block是被AFURLSessionManagerTaskDelegate對象引用毫别。而AFURLSessionManagerTaskDelegatemutableTaskDelegatesKeyedByTaskIdentifier字典引用,AFN在block執(zhí)行完后庞萍,mutableTaskDelegatesKeyedByTaskIdentifier字典會移除AFURLSessionManagerTaskDelegate對象拧烦,這樣block也被釋放。所以不存在循環(huán)引用的問題钝计。具體的代碼恋博,請大家去看看 AF 的源碼就知道了。

2.用self 調(diào)用 block 就會造成循環(huán)引用

??并不是所有通過self調(diào)用帶有block的方法會引起循環(huán)引用私恬,因?yàn)檠h(huán)引用的就是要雙方互相引用债沮,需要看方法內(nèi)部有沒有持有self
舉個??:

[self dismissViewControllerAnimated:YES completion:^{
    NSLog(@"%@",self);
}];

??這里乍一看感覺好像循環(huán)引用了本鸣,其實(shí)并沒有疫衩。這里雖然 block 持有對象self,但是self 并沒有持有 block荣德,所有 selfblock 并沒有互相引用闷煤,也就不存在循環(huán)引用了。

3.block中只要不用self就不會造成循環(huán)引用

??在block中并不只是self會造成循環(huán)引用涮瞻,用下劃線調(diào)用屬性也會出現(xiàn)循環(huán)引用鲤拿,效果和使用self是一樣的。

如何避免循環(huán)引用

1.block的外部對象加上week修飾

??外部對象加上week修飾署咽,使用全局弱指針指向一個局部強(qiáng)引用對象近顷,這樣局部變量在超出其作用域后也不會被銷毀。所以不會造成循環(huán)引用宁否。

2.手動將對象置為nil

??將對象置為nil氛濒。在ARC中湾揽,被置為nil的對象會被銷毀。所有這樣就會不會造成 block 和對象相互引用的情況了。但是這種方法不推薦鄙皇,因?yàn)槿绻@個對象存在多個block 的時(shí)候就會出現(xiàn)問題将鸵。

3.使用完之后將block置為空

??和上一種方法同理爹殊,只是將block 置為 nil霎槐,這樣 block就被銷毀了,也不會存在循環(huán)引用了青伤《搅可以在封裝block的時(shí)候,可以考慮使用完馬上置空當(dāng)前使用的block狠角,這樣使用的時(shí)候就不需要考慮循環(huán)引用的問題号杠。這個方法很暴力,喜歡暴力美學(xué)的人可以嘗試此方法。

總結(jié)

??使用block的時(shí)候姨蟋,要避免造成循環(huán)引用屉凯,如果造成循環(huán)引用要知道用哪種方法去修改。不過最好的修改方法就是不用 block

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眼溶,一起剝皮案震驚了整個濱河市悠砚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堂飞,老刑警劉巖灌旧,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绰筛,居然都是意外死亡枢泰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門铝噩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衡蚂,“玉大人,你說我怎么就攤上這事骏庸∶祝” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵具被,是天一觀的道長玻募。 經(jīng)常有香客問我,道長硬猫,這世上最難降的妖魔是什么补箍? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任改执,我火速辦了婚禮啸蜜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辈挂。我一直安慰自己衬横,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布终蒂。 她就那樣靜靜地躺著蜂林,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拇泣。 梳的紋絲不亂的頭發(fā)上噪叙,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機(jī)與錄音霉翔,去河邊找鬼睁蕾。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的子眶。 我是一名探鬼主播瀑凝,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼臭杰!你這毒婦竟也來了粤咪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤渴杆,失蹤者是張志新(化名)和其女友劉穎寥枝,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體将塑,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脉顿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了点寥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艾疟。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖敢辩,靈堂內(nèi)的尸體忽然破棺而出蔽莱,到底是詐尸還是另有隱情,我是刑警寧澤戚长,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布盗冷,位于F島的核電站,受9級特大地震影響同廉,放射性物質(zhì)發(fā)生泄漏仪糖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一迫肖、第九天 我趴在偏房一處隱蔽的房頂上張望锅劝。 院中可真熱鬧,春花似錦蟆湖、人聲如沸故爵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诬垂。三九已至,卻和暖如春伦仍,著一層夾襖步出監(jiān)牢的瞬間结窘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工充蓝, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留隧枫,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像悠垛,于是被迫代替她去往敵國和親线定。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容