block循环引用的三种状况和处理办法

刚入职在看已经上线的项目,其中用到block进行快捷回调的作法很经常使用,可是Xcode都给给以了以下【循环引用】的警告(以下)的状况,结合网络上的查找和本身的理解,进行总结以下。网络

//this

Capturing 'self' strongly in this block is likely to lead to a retain cycleurl

 

出现这种状况的缘由主要是:由于block的特性,声明block的对象都会以copy的形式持有block,而block对于它内部的对象也会进行强引用,从而致使了循环引用。下面举具体的例子来讲明。spa

一、self的block属性内部引用self,互相引用;.net

self.myTitle = self.title;

    self.backViewController = ^{
        [self backProViewController];//【【【循环引用】】】
};

二、该例子中showImage为控制器方法内的本地(局部)变量,showImage强持有block,block再强持有showImage,致使循环引用code

 1 -(void)imageTapCilck
 2 {
 3     NSString* imageUrl = [dataSoure objectForKey:@"chargeStandard"];
 4     if (imageUrl) {
 5         FLYShowImageViewController* showImage = [[FLYShowImageViewController alloc]initWithNibName:@"FLYShowImageViewController" bundle:nil];
 6         showImage.imageUrl = imageUrl;
 7         showImage.cancel = ^{
 8             [showImage dismissViewControllerAnimated:NO completion:^{//【【【循环引用】】】
 9 10  }]; 11  }; 12 [self presentViewController:showImage animated:NO completion:^{ 13 14  }]; 15  } 16 17 }

三、下面的例子中有2个循环引用警告,例中topView、_scrollView均为实例(成员)变量;orm

第一个:实例变量topView强持有block,block强持有实例变量_scrollView,而控制器强持有两个实例变量topView和_scrollView,造成循环引用;对象

第二个self强持有block,block强持有实例变量_scrollView,self强持有实例变量_scrollView,造成循环引用blog

 1 -(void)initTopView
 2 {
 3     topView = [[FLYConferenceCallSegmentView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, 70)];
 4     NSDictionary* dic1 = @{@"title":@"集团通信录",@"url":@"group_contact_normal",@"selected_url":@"group_contact_pressed"};
 5     NSDictionary* dic2 = @{@"title":@"手机通信录",@"url":@"local_contact_normal",@"selected_url":@"local_contact_pressed"};
 6     NSDictionary* dic3 = @{@"title":@"手工输入",@"url":@"manual_normal",@"selected_url":@"manual_pressed"};
 7     NSArray* array = @[dic1,dic2,dic3];
 8     topView.selectForIndex = ^(NSInteger index){//【【【循环引用1】】】
 9         _scrollView.contentOffset = CGPointMake(index*_scrollView.frame.size.width, 0);
10     };
11     topView.array = array;
12     [topView reloadView];
13     
14     self.selectTest = ^(NSInteger index){
15         _scrollView.contentOffset = CGPointMake(index*_scrollView.frame.size.width, 0);//【【【循环引用2】】】
16  }; 17 18  [self addSubview:topView]; 19 20 }

在使用block进行回调时,出现这样的状况是不免的,有时候可能还会在block内部强引用多个实例变量和self,解决的办法是同样的,即在block的内部使用弱引用修饰符__weak,针对上面的例子,举例以下:get

若是block持有self,使用下面语句获取self的弱引用weakSelf替换block中的self便可;

__weak typeof(self) weakSelf = self;

同理,其余被block强引用的对象都须要获取弱引用后代入block。

__weak typeof(UIScrollView *) weak_scrollView = _scrollView;

 

一个疑问:有另一个作法是:在获取对象的弱引用后,在block的内部再转成强引用在block中使用,这样的最终结果会怎么样,不得而知。

    __weak typeof(self) weakSelf = self;

    topView.selectForIndex = ^(NSInteger index){
        __strong typeof(self) strongSelf = weakSelf;
        [strongSelf initScrollView];
    };

 

 

一个关于block的详细解读请参考:Block的引用循环问题 (ARC & non-ARC)【wildfireli】 。

相关文章
相关标签/搜索