在block中使用self怎麼避免循環引用

內存問題始終是軟件開發中的頭等大事,iOS開發中也不例外,在面試中也是必問的問題。今天咱們主要來說講Block中涉及的循環引用問題。當咱們本身一開始寫代碼的時候,可能會大量在block中使用self,可是當看到別人優秀的代碼的時候,發現別人經常不是用self,而使用weakSelf. 爲何呢?本文的示例代碼上傳至 https://github.com/chenyufeng1991/Block_WeakSelf 。 ios

       首先我先來講說內存管理的原則:git

1.默認使用strong,可選weak。strong下無論成員變量仍是屬性,每次使用指針指向一個對象,就會自動調用retain,並對舊對象調用release,在須要釋放的時候設爲nil。github

2.避免循環引用,不然手動設置nil釋放。面試

3.建立block匿名函數以前通常須要對self進行weak化,不然形成循環引用沒法釋放controller。安全

      首先Xcode爲咱們提供了良好的編譯環境,若是代碼中有可能出現循環引用的地方,Xcode會給咱們警告:「Capturing 'self' strongly in this block is likely to lead to a retain cycle」.如圖:app

函數

 

      block中的循環引用是這樣的:某個對象有一個copy或者strong成員變量或者屬性,這時block內部直接引用了成員變量或者self,這樣就產生了self持有block成員,block成員持有self,就會致使循環引用。由於self自己就是一個strong類型的變量。蘋果官方的建議是:傳進block以前,把self轉換成weak automatic的變量,這樣在block中就不會出現對self的強引用。若是在block執行完成以前,self被釋放,weakSelf也會置爲nil。weak類型相對比較安全,由於能夠在釋放後自動置爲nil,不會引發野指針。那麼如何來聲明呢?this

 1.atom

[cpp] view plain copyspa

 print?在CODE上查看代碼片派生到個人代碼片

  1. __weak typeof(self) weakSelf = self;  

 

 

這句話的意思是聲明瞭一個self類型的weak指針,名字叫作weakSelf.  typeof是用來求參數類型的,這裏也就是來求self的類型。這樣定義出的weakSelf就是和self是一個類型,而且是原self的一個弱引用。

 

2.

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. __weak typeof(&*self) weakSelf = self;  

 

 

3.

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. __weak MyViewController *weakSelf = self;  


 

 

下面我經過代碼演示一下:

(1)聲明幾個block和一個屬性:

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. @interface ViewController (){  
  2.   
  3.     void(^myBlock1)(void);//該block參數爲void,返回值爲void  
  4.     void(^myBlock2)(void);  
  5.     void(^myBlock3)(void);  
  6. }  
  7.   
  8. @property (nonatomic,copy) NSString *person;  
  9.   
  10. @end  


(2)使用weakSelf不會引發循環引用:

 

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. __weak typeof(self) weakSelf = self;  
  2.   
  3. NSLog(@"init--> value:%@,address=%p,self=%p",self.person,self.person,self);  
  4.   
  5. myBlock1 = ^(void){  
  6.     //這樣不會形成循環引用  
  7.     NSLog(@"execute1--> value:%@,address=%p,weakSelf=%p",weakSelf.person,weakSelf.person,weakSelf);  
  8. };  


 

 

(3)直接使用self,會循環引用:Xcode會給警告

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. myBlock2 = ^(void){  
  2.     //這樣形成循環引用  
  3.     NSLog(@"execute2--> value:%@,address=%p,self=%p",self.person,self.person,self);  
  4. };  


 

 

(4)要執行的方法抽取出來,也不會循環引用:

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. myBlock3 = ^(void){  
  2.     //這樣也不會形成循環引用,已經抽取出要執行的方法  
  3.     [weakSelf myBlock3Func];  
  4. };  

 

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. - (void)myBlock3Func{  
  2.   
  3.     NSLog(@"execute3--> value:%@,address=%p,self=%p",self.person,self.person,self);  
  4. }  


 

 

(5)block不是self的屬性或者變量時,在block內使用self也不會循環引用:

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. //block不是self的屬性時,block內部使用self也不是循環引用  
  2. Animal *animal = [[Animal alloc] init];  
  3. animal.animalBlock = ^(void){  
  4.   
  5.     NSLog(@"animal--> value:%@,address=%p,self=%p",self.person,self.person,self);  
  6. };  


 

 

(6)block的調用以下:

 

[cpp] view plain copy

 print?在CODE上查看代碼片派生到個人代碼片

  1. myBlock1();  
  2. myBlock2();  
  3. myBlock3();  
  4.   
  5. animal.animalBlock();      
相關文章
相關標籤/搜索