Block的Retain Cycle的解決方法

一個使用Block語法的實例變量,在引用另一個實例變量的時候,經常會引起retain cycle。這個問題在使用ASIHTTPRequest的block語法的時候會時不時的碰到。這個問題困擾了我這個小白很久。終於有一天,在Advanced Mac OS X Programming上,看到了這個問題的解決方案。

先用代碼描述一下症狀:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* ViewController.h */ 
#import <UIKit/UIKit.h>

typedef void (^ABlock)(void); //定義一個簡單的Block

@interface ViewController : UIViewController {
    NSMutableArray *_items;
    ABlock _block;
}

@end

/* ViewController.m */ 

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _items = [[NSMutableArray alloc] init];
    _block = ^{
        [_items addObject:@"Hello!"]; //_block引用了_items,導致retain cycle。
    };
}

@end

Xcode在編譯以上程序的時候會給出一個警告:Captureing ‘self’ strongly in this block is likely to lead to a retain cycle。原因是_items實際上是self->items_block對象在創建的時候會被retain一次,因此會導致self也被retain一次。這樣就形成了一個retain cycle。

解決方法就是,創建一個本地變量blockSelf,指向self,然後用結構體語法訪問實例變量。代碼如下:

1
2
3
4
__block ViewController *blockSelf = self;
_block = ^{
    [blockSelf->_items addObject:@"Hello!"];
};

這麼修改之後,blockSelf是本地變量,是弱引用,因此在_blockretain的時候,並不會增加retain count,所以retain cycle就解除了,Xcode也不再出現警告了,問題解決。

注:本文並非原創,詳情請參閱Advanced Mac OS X Programming,第92頁“Block Retain Cycles”。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章