在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();      
相关文章
相关标签/搜索