1. 程式人生 > >Block 迴圈引用淺談

Block 迴圈引用淺談

Block 的迴圈引用問題,想必使用過 Block,幾乎都遇到過。今天CodeReview時,發現還存在迴圈引用的問題。故簡單記錄如下:

一、迴圈引用的原因

簡單來說就是,【互相持有,造成記憶體不釋放】。

如:self --持有--> block --持有--> self  形成了一個環,中間還可能穿插其他物件,反正最後形成了一個閉環,造成誰也不撒手,故記憶體永遠不釋放。

二、解決方案

也是一句話,砍掉任一一個鏈,破壞這個互相持有的閉環。

1、self 不持有 block

    void (^testBlock)() = ^(){
       self.testStr = @"Hello block";
    };
    testBlock(@"");

2、block 不強持有 self : weakSelf & strongSelf

__weak __typeof__(self) weakSelf = self;

__strong typeof(weakSelf) strongSelf = weakSelf;
即 Block 裡對 self 為弱引用,不持有 self,即 self 的引用計數不會+1. 僅引用一次,用weakSelf ,多次引用,則用 strongSelf 。strongSelf 是為了保證在 block 執行過程中,self 不會再變化。 至於二者區別,可以隨便網上查一下,有很多人都對此進行了分享。
     __weak __typeof__(self) weakSelf = self;
    self.block = ^(){
        __strong typeof(weakSelf) strongSelf = weakSelf;
        testStr0 = @"這是 test 字串";
        NSLog(@"%@",strongSelf->testStr0);
    };
    self.block();
另,在 block 中對 self 的引用情況,包括使用 self 的屬性,呼叫 self 的方法,以及使用 self 的成員變數。
    __weak __typeof__(self) weakSelf = self;
    self.block = ^(){
        __strong typeof(weakSelf) strongSelf = weakSelf;
        strongSelf->p_testStr = @"這是成員變數";
        NSLog(@"%@",strongSelf->p_testStr);
    };
    self.block();

3、block 執行完後,置為 nil

    self.testStr = @"Test Str";
    self.block = ^(){
        NSLog(@"%@",self.testStr);
    };
    self.block();
    self.block = nil;

三、擴充套件

在總結迴圈引用的問題時,突發奇想這樣一種情況: 若 block 中,有用了 GCD , GCD 的 block 裡又用到了 self ,那該如何判斷是否存在迴圈引用呢? 如:
    void (^testBlock)() = ^(){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5. * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.testStr = @"Hello block";
            NSLog(@"%@>>>gcd執行了",self.testStr);
        });
    };
    testBlock(@"");
再如:
    self.block = ^(){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5. * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.testStr = @"Hello block";
            NSLog(@"%@>>>gcd執行了",self.testStr);
        });
    };
    self.block();
其實,分析其持有關係,看有沒有形成互相持有的環,若存在環,那肯定就迴圈引用了。 1、testBlock --持有-->  GCD --持有-->  self 【沒有形成環,不存在迴圈引用】 2、self--持有--> block --持有--> GCD --持有--> self 【形成了環,故存在迴圈引用】 解決迴圈引用的方式還是如上面所述的三點即可。
附上 demo ,演示上文中提到的 block 中解決迴圈引用的方式。