1. 程式人生 > >Block中weak/strong self的用法

Block中weak/strong self的用法

在用到block時,我們經常會有這樣一種用法

//請忽略不重要的程式碼行
__weak __typeof(self)weakSelf = self;
blk_t blk = ^() {
    __strong __typeof(weakSelf)strongSelf = weakSelf;
}

其中比較有意思的地方就是先在block外定義一個弱引用的self指向self,然後在block內定義一個強引用的self指向weakSelf。那麼就針對這兩點來講講block裡weak/strong self的問題。首先宣告:上面提到的用法很保險,沒有什麼問題。

weakSelf->self
我們都知道,block比較常見的一個問題就是迴圈引用問題,簡單描述即:self已經持有了block,如果block裡再使用self,self將被block截獲,然後block持有self,導致迴圈引用。

那麼我們在block外定義一個weakSelf指向self,然後block就會截獲這個weakSelf,不會再產生迴圈引用的問題。

strongSelf->weakSelf
block中還有個有意思的點就是block截獲的變數在超出其作用域後仍能使用(比如block截獲了self,然後block又被傳遞到其它地方使用,此時self按理已經釋放)。這其實是因為系統會自動的根據情況將block從棧拷貝到堆中並強引用它截獲的變數(一般我們的block最開始都是在棧中的),我們知道棧的記憶體是由系統管理的,而堆是由程式猿管理的,所以實現了變數超出作用域仍能使用。

根據這個說法,我們應該不需要自己強引用weakSelf,我們的weakSelf應該也會被block自己強引用,那我們何必多次一舉呢…事實也確實如此,block確實強引用了我們的weakSelf,就算我們不自己強引用weakSelf程式碼也不會有問題。但是我們在上一段中提到了系統拷貝block是有條件的,有些條件下系統不會自動拷貝block,這種情況下weakSelf超出作用域將被釋放。那麼哪些情況下系統不會自動copy呢?最常見的一個——block作為引數傳遞,這也是使用頻率非常高的一個點。所以,自己動手是為了更加保險。

下面列出block能夠拷貝的情況:
1、呼叫block的copy方法
2、block作為返回值
3、block賦值時
4、Cocoa框架中方法名中含有usingBlock的方法
5、GCD中

關於GCD中block再提一點:
GCD中的block並沒有直接或間接被self強引用的,所以不會存在迴圈引用,故不需要weakSelf;又GCD中block能夠自動copy,所以self超出作用域仍可用,故不需要寫strongSelf

總結:
weakSelf是為了解決迴圈引用
strongSelf是為了保證任何情況下self在超出作用域後仍能夠使用