剛入職在看已經上線的項目,其中用到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】 。