Block 的循環引用

Block是在棧上生成的,因此通常使用copy方法把Block複製到堆上,避免Block被馬上釋放。spa

Block會對內部的變量造成強引用,而若是同時該變量又持有這個Block,就會致使循環引用而沒法釋放,從而致使內存泄露。code

最多見的就是self持有Block,而又在Block內部調用self的方法或屬性,那selfBlock就會造成循環引用而沒法釋放。因爲咱們習慣在dealloc中釋放對象,可是即便在dealloc中將Block釋放也沒用,由於selfdealloc根本不會跑進去。好比:對象

1 self.MyBlock = ^void(){
2  
3   [self doSomething];
4 };

 

其實,最簡單的解決方法就是在self的某個非dealloc方法中將Block主動釋放,並在須要釋放self以前調用這個方法,這樣纔能有效的解除引用。可是這種方法使用起來比較麻煩,並且很容易忘記調用。blog

因此咱們通常是在Block中使用弱引用的self。下面分別介紹ARCMRC中在Block中使用弱引用self的方法。內存

ARC

1 __weak typeof(self) weakSelf = self;
2  
3 self.MyBlock = ^void(){
4  
5 __strong typeof(self) strongSelf = weakSelf;
6  
7   [strongSelf doSomething];
8 };

這樣作的好處是沒必要在Block直接使用self,這樣就不會對self進行強引用,只要self須要釋放,self就會自動釋放,Block也會自動釋放。ARC中,進入Block前,須要使用__weakself進行弱引用,並在Block中使用__strongweakSelf進行強引用。開發

這樣作的另外一個好處是,在ARC中使用__weak以後,若是self在某個地方被釋放了,那weakSelf也會被自動置爲nil,這樣即便在Block中使用weakSelf,也不會訪問錯誤。get

而在Block中使用__strong則是爲了不在使用Block的過程當中self被釋放致使訪問出錯。class

 

MRC


1
__block typeof(self) blockSelf = self; 2 3 self.MyBlock = ^void(){ 4 5   if (!malloc_zone_from_ptr(blockSelf)) 6   return; 7 8   __strong typeof(self) strongSelf = blockSelf; 9 10   [strongSelf doSomething]; 11 };

其實,MRC的基本思路和ARC是同樣的。有兩處不一樣:變量

  1. MRC中使用__block而不是__weak進行弱引用,由於在ARC中使用__block會對該對象進行強引用。循環

  2. MRCBlock中使用malloc_zone_from_ptr()方法判斷blockSelf是否已經被釋放,由於MRC不會對已釋放的對象自動置爲nil


 

可見,不管是MRC仍是ARC,解決方法都是相似的。雖然Block的使用增長了簡潔性和便利性,但使用Block的過程當中也要時刻注意避免內存泄露。

How Do I Declare A Block in Objective-C? 總結了聲明Block的幾種格式,在開發過程當中能夠參考使用。

相關文章
相關標籤/搜索