天天看點

block-循環引用

在ARC機制下,app的記憶體管理由作業系統進行管理,不需要程式員手動的管理記憶體,友善了開發.盡管,自動釋放記憶體很友善,但是并非絕對安全,絕對不會産生記憶體洩露。大部分導緻iOS對象無法按預期釋放的一個無形殺手是——循環引用。循環引用可以簡單了解為A引用了B,而B又引用了A,雙方都同時保持對方的一個強引用,導緻任何時候引用計數都不為0,始終無法釋放。

下面我們介紹下block代碼塊,引起的循環引用以及解決辦法

block在copy時都會對block内部用到的對象進行強引用。第一種容易引起循環引用的一般表現為,某個類将block作為自己的屬性變量,然後該類在block的方法體裡面又使用了該類本身,簡單說就是self.MyBlock = ^(Type var){[self dosomething]; 或者self.otherVar = XXX;或者_otherVar = …}, 造成了self 擁有一個block的時候,在block 又調用self的方法。block的這種循環引用會被編譯器捕捉到并及時提醒。

舉例如下(People類):

block-循環引用

我們可以看出在block的實作内部又使用了People類(self)的name屬性,這個時候,編譯器提醒給出了相關的警告.

解決方法:

block-循環引用

通過使用_weak聲明一個代替self的新變量代替原先的self,命名為weakSelf。通過這種方式告訴block,不要在block内部對self進行強制強引用.

這種循環引用的事例圖為:

block-循環引用

第二種情況為:例如self 有一個button ,而你有要 調用 button的某個東西設定.[self.button ^{ }]由于某些原因,你又要在這個block裡調用self的其他控件,例如self.textField.text = @”text”;就造成了訊混引用。(即:控制器中有一個控件,在這個控件中又通路了控制器的其他控件).例如AlertController中的Action對象通路AlertController的textField對象.

為了進行示範的事例:首先我們定義了一個UIAlertController的子類(AlertController),并實作它的dealloc方法

- (void)dealloc{
    NSLog(@"alertController dealloc");
}
           
block-循環引用

在主要制器中建立AlertController,并實作點選确認的方法(擷取其上的文本框内容資訊)

block-循環引用

點選确認後,列印如下

block-循環引用

我們發現在銷毀AlertController的時候,AlertController并沒有釋放,導緻了記憶體的洩露.

修改為如下方式,點選确認後結果為:

block-循環引用

可以看出,對象得到釋放.

沒有修改之前的事例圖為:

block-循環引用

解決循環引用後

block-循環引用

解決方法

簡而言之就一句話的事情:

__weak typeof (self) weakSelf = self;