內(nèi)存管理之 Block(weak-strong dance)

如果覺得我寫的還不錯,請關(guān)注我的新浪微博@小橘爺,最新文章即時推送~

謹(jǐn)以此文獻(xiàn)給酷愛 Block 的戰(zhàn)友們——小橘爺

前言

Block 因為性能好,使用方便而為大多數(shù) iOS 開發(fā)者所喜愛,但是 Block 的使用并非大家所想的那么簡單。接下來就讓我們從內(nèi)存管理的角度看看,如何在 ARC 的環(huán)境下使用好 Block。

防止循環(huán)引用

眾所周知,Block 在使用的時候默認(rèn)會使對象的引用計數(shù)加一,所以我們需要使用 __weak 關(guān)鍵字來防止對象(主要是指擁有此 Block 所在對象的控制器)和 Block 循環(huán)引用。如下代碼所示:

MyViewController *myController = [[MyViewController alloc] init…];
 // ...
MyViewController * __weak weakMyViewController = myController;
myController.completionHandler = ^(NSInteger result) {
    [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
};

但是絕大多數(shù)人對于 Block 的使用就到此為止了……如果我要在 Block 里 removeObserver 你猜會發(fā)生什么?

崩潰!因為 weakMyViewController 被弱引用,在 ARC 的環(huán)境下(尤其還有可能伴隨著多線程)隨時可能被釋放,這樣就會導(dǎo)致因為解除 KVO 而引起 Crash。

雖然是小概率的事件,但是對于一個嚴(yán)格要求自己的程序員,再小概率的 Crash 觸發(fā)也是不能放過的!

這時候你可能會想,我加一個if判斷,看一下 weakMyViewController 是否為 nil 不就行了,比如這樣:

MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyViewController = myController;
myController.completionHandler = ^(NSInteger result) {
    if (weakMyViewController != nil) {
        //在這里removeObserver
    }  
    [weakMyViewController dismissViewControllerAnimated:YES completion:nil];
};

我可以很負(fù)責(zé)任的告訴你,這條路是走不通的,因為 weakMyViewController 隨時有可能被系統(tǒng) release…… 那么我們究竟應(yīng)該怎么辦呢?

weak-strong dance

這時候我們進(jìn)入到 AFNetworking 這個框架里,看看大牛是如何解決這個問題的~

__weak __typeof(self)weakSelf = self;
    AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
    __strong __typeof(weakSelf)strongSelf = weakSelf;

    strongSelf.networkReachabilityStatus = status;
    if (strongSelf.networkReachabilityStatusBlock) {
        strongSelf.networkReachabilityStatusBlock(status);
    }

};

__strong __typeof(weakSelf)strongSelf = weakSelf;就是解決這個問題的關(guān)鍵~先將強引用的對象轉(zhuǎn)為弱引用指針,防止了 Block 和對象之間的循環(huán)引用。再在 Block 的第一句代碼出將 weakSelf 的弱引用轉(zhuǎn)換成 strongSelf 這樣的強引用指針,防止了多線程和 ARC 環(huán)境下弱引用隨時被釋放的問題(因為強引用的引用計數(shù)至少為1)。

這里大家一定要有一個認(rèn)識,weakSelf 位于 Block 的外面,strongSelf 位于 Block 的里面。從內(nèi)存管理的角度來看,weakSelf 是要比 strongSelf 的聲明周期要長的。這樣就形成了從弱引用到強引用,再從強引用到弱引用的一種變化,也稱作 weak-strong dance。

那么到此就結(jié)束了嗎?

蘋果官方文檔的解釋(Transitioning to ARC Release Notes)

為了以防萬一,我們還是來查閱一下蘋果官方文檔吧,畢竟這才是最權(quán)威的。

在里面我們看到了這樣一串代碼:

MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
    MyViewController *strongMyController = weakMyController;
        if (strongMyController) {
            // ...
            [strongMyController dismissViewControllerAnimated:YES completion:nil];
            // ...
        }
        else {
            // Probably nothing...
        }
};

**if (strongMyController) **是這段代碼的亮點。之所以在Block的代碼執(zhí)行之前加上這樣一個判斷,就是為了防止在把 weakSelf 轉(zhuǎn)換成 strongSelf 之前 weakSelf 就已經(jīng)為 nil 了,這樣才能確保萬無一失。

所以說,信自己不如信大牛,信大牛不如信蘋果有空,就多翻翻官方文檔吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容