閱讀772 返回首頁    go 阿裏雲 go 技術社區[雲棲]


block循環引用解決


block循環引用解決

實驗代碼


@interface ViewController ()
@property (nonatomic, strong) TestNetworkBlock *testNetwork;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.testNetwork = [[TestNetworkBlock alloc] init];
    
    [self.testNetwork ceshi];
    [self.testNetwork release], self.testNetwork = nil;
}
@end

@interface TestNetworkBlock ()
{
    countBlock _countBlock;
}

@property (nonatomic, strong) NSString *strTest;


@end


@implementation TestNetworkBlock


- (id) init
{
    self = [super init];
    if (self)
    {
        self.strTest = @"我的測試";
        __weak TestNetworkBlock *weakSelf = self;
        _countBlock = ^(int i){
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
                sleep(5);
                NSString *string = [weakSelf zhixing:i];
                NSLog(@"string=====%@", string);
            });
        };
    }
    return self;
}

- (NSString *) zhixing:(int) i
{
    NSString *string = [NSString stringWithFormat:@"%@%d", self.strTest, i];
    
    return string;
}

- (void) ceshi
{
    _countBlock(5);
}

- (void) dealloc
{  
    NSLog(@"======dealloc");
}
@end

問題剖析:

多線程調用,block外麵聲明了weakSelf,則block內部對self的引用為指針引用,當外部[self.testNetwork release], self.testNetwork = nil;時,weakSelf為nil,所以導致運行失敗。

第二種:block改為self引用


_countBlock = ^(int i){
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
                sleep(5);
                NSString *string = [self zhixing:i];
                NSLog(@"string=====%@", string);
            });
        };

問題剖析

_countBlock為self對象,self強引用了_countBlock,同時_countBlock又怕裏麵self釋放,所以block體裏麵會強引用self。導致循環引用,內存一直不會被釋放,dealloc也不會被調用。

正確做法:block內部加入bSelf強引用指針


 __weak TestNetworkBlock *weakSelf = self;
_countBlock = ^(int i){
            TestNetworkBlock *bSelf = weakSelf;
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
                sleep(5);
                NSString *string = [bSelf zhixing:i];
                NSLog(@"string=====%@", string);
            });
        };

問題剖析

在 block 之前定義對 self 的一個弱引用 wSelf,因為是弱引用,所以當 self 被釋放時 wSelf 會變為nil;
在block體內部聲明一個強引用對象bself指向該wSelf。bSelf隻會在block內部執行完畢才會消亡,這樣就保證了self對象被外部其他線程釋放掉的情況。又避免了循環引用,因為在block執行完,會釋放掉bSelf。

最後更新:2017-08-13 22:34:03

  上一篇:go  perl信號量實現進程間通信
  下一篇:go  6個大數據處理分析的最好工具