标签:
刚入职在看已经上线的项目,其中用到block进行快捷回调的做法很常用,但是Xcode都给给以了如下【循环引用】的警告(如下)的情况,结合网络上的查找和自己的理解,进行总结如下。
//
Capturing ‘self‘ strongly in this block is likely to lead to a retain cycle
出现这种情况的原因主要是:因为block的特性,声明block的对象都会以copy的形式持有block,而block对于它内部的对象也会进行强引用,从而导致了循环引用。下面举具体的例子来说明。
1、self的block属性内部引用self,互相引用;
self.myTitle = self.title; self.backViewController = ^{ [self backProViewController];//【【【循环引用】】】
};
2、该例子中showImage为控制器方法内的本地(局部)变量,showImage强持有block,block再强持有showImage,导致循环引用
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 }
3、下面的例子中有2个循环引用警告,例中topView、_scrollView均为实例(成员)变量;
第一个:实例变量topView强持有block,block强持有实例变量_scrollView,而控制器强持有两个实例变量topView和_scrollView,形成循环引用;
第二个self强持有block,block强持有实例变量_scrollView,self强持有实例变量_scrollView,形成循环引用
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,针对上面的例子,举例如下:
如果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】 。
标签:
原文地址:http://www.cnblogs.com/beforeold/p/4515358.html