Weak-Strong Dance中Strong解析

在使用Block時常趁6啵可以看到Weak-Strong Dance的用法, 很多的文章以及官方文檔都舉例了這樣做的原因. 但是還尚未發(fā)現(xiàn)有對strong進行講解的. 下面就舉個栗子具體分析下為什么加strong以及何時起作用

首先放上兩個類似 ReactiveCocoa 中 定義weakify和strongify的宏 以便下文用到

#define WeakObj(o) autoreleasepool{} __weak typeof(o) weak##o = o
#define StrongObj(o) autoreleasepool{} __strong typeof(o) o = weak##o


一党觅、weak的作用(代碼+注解 簡單跳過)

防止被block捕獲(會導(dǎo)致引用計數(shù)加1), 打破循環(huán)引用(retain cycle)

// DeallocMonitor繼承NSObject, 僅重寫其dealloc方法, 并在其中打印其被釋放日志
DeallocMonitor *object1 = [DeallocMonitor new];
DeallocMonitor *object2 = [DeallocMonitor new];
@WeakObj(object2);//__weak typeof(object2) weakobject2 = object2;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        // object1被block捕獲, 引用計數(shù)加1, 外部作用域結(jié)束時仍未被釋放, 直至該Block執(zhí)行完畢才被釋放
        NSLog(@"5s已到, %@該被釋放勒", object1);
        // weakobject2被weak 修飾, 其指向的object2對象的引用計數(shù)不會增加, 當(dāng)外部作用域結(jié)束時就已被釋放
        NSLog(@"5s已到, %@早已被釋放, 此處為null", weakobject2);
});
// 外部作用域結(jié)束

二、為何要加strong, 其何時才起作用?

加strong的原因想必大家都知道是為了防止block執(zhí)行過程中 __weak typeof(object) weakObject指向的對象突然被釋放了, 這就會導(dǎo)致block中的代碼運行結(jié)果出現(xiàn)意想不到的結(jié)果(比如一些代碼執(zhí)行有效, 其余代碼執(zhí)行無效; 弱引用的對象因為為nil而導(dǎo)致的crash等.)

2.1 即使加了strong, 也不能保證weakObject指向的對象不會被釋放

只能確保在block執(zhí)行期間, weakObject指向的對象有效(不會被釋放)

下面這段代碼就是在block中用strong申明的對象強引用一次weakObject, 但修飾對象在block執(zhí)行前就已經(jīng)被釋放的栗子

// DeallocMonitor繼承NSObject, 僅重寫其dealloc方法, 并在其中打印其被釋放日志
DeallocMonitor *object = [DeallocMonitor new];
@WeakObj(object);// weakobject
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        // 該strongObj的申明僅在block執(zhí)行時才見效, 而外部作用域一結(jié)束object就已經(jīng)被釋放了, 所以然并卵
       @StrongObj(object);
        /* weakobject用 weak修飾, 故其引用計數(shù)不變, 
          上邊的宏本意是申明一個新的object局域變量對weakobject指向的原object進行強引用..
          按理 原object引用計數(shù)應(yīng)該會加1, 可是它還沒等到被強引用時就已經(jīng)掛掉了
        */
        NSLog(@"5s已到, %@然后早已被釋放, 此處為null", object);
});
// 外部作用域結(jié)束
2.2 Block內(nèi)部申明的強引用指針變量指向weakObject僅在block執(zhí)行時才有效

定義該Block的時strongObj宏還尚未使原對象引用計數(shù)加1! 那么strongObj宏生效時的表現(xiàn)是什么樣子的呢? 繼續(xù)上代碼

// 該段代碼主要是打了一個時間差, 以模擬strong申明起作用的情形

// DeallocMonitor繼承NSObject, 僅重寫其dealloc方法, 并在其中打印其被釋放日志
DeallocMonitor *object = [DeallocMonitor new];
// 保證外部作用域結(jié)束的2.5秒(無限接近..)內(nèi)object不會被釋放
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.5 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        NSLog(@"果斷強引用object: %@\n 還能再多堅持2.5s", object);
});
@WeakObj(object);// weakobject
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
       @StrongObj(object);// __strong typeof(object) object = weakobject
        sleep(3);// 卡個3s
        // 此處就不會像上一段代碼那樣, 強引用一個為nil的object, 故weakobject指向的對象引用計數(shù)加1, 直到該block運行完, 才會被釋放
        NSLog(@"5s已到, %@打印完這個日志就飛升了", object);
});
// 外部作用域結(jié)束
2.3 有多少個嵌套block就應(yīng)該申明多少對weak-strong

假定我們在最外層block使用的一對weak-strong, 且外層block內(nèi)還有一個block(沒有用weak-strong)引用到了strongObj宏申明的局域變量object, 并假設(shè)原對象在外層block開始運行前一直存活, 這就會導(dǎo)致內(nèi)層block捕獲到局域變量object并使其指向?qū)ο蟮囊糜嫈?shù)加1, 因為內(nèi)層block捕獲到了外層block中申明的object(強引用), 就跟外層block會捕獲到外部強引用變量指向的對象一樣一樣的

DeallocMonitor *object = [DeallocMonitor new];
@WeakObj(object);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
       @StrongObj(object);// 因為block運行時, weakObject指向?qū)ο笠琅f存在, 故該強引用使其引用計數(shù)加1
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
            // 這一層block 發(fā)現(xiàn)上邊的object是強引用, 導(dǎo)致捕獲到其指向?qū)ο? 使其引用計數(shù)在該內(nèi)層block尚未執(zhí)行時就加1了
            NSLog(@"打印完這個日志, %@才被釋放", object);
        });
        NSLog(@"%@外層block結(jié)束, 引用計數(shù)減一", object);
});
sleep(3);
// 外部作用域所在線程小歇一會, 確保object存活3s, 作用域結(jié)束

所以嵌套block時 萬萬要小心, 不要漏寫了. 另外weak-strong要成對出現(xiàn), 不然少一個strong, 都有可能為此付出代價

2.4 遺漏補缺
  1. 在block中對外部weakObject進行強引用(strong修飾)的結(jié)果是使weakObject指向的原對象的引用計數(shù)加1, 因為weakObject指針指向的是原對象在堆中的存儲地址
  2. block 不會對弱引用指針變量指向的對象進行捕獲
2.5 block的相關(guān)知識, 個人推薦書籍章節(jié)
  • Effective-ObjectiveC(Item 37: Understand Blocks)
  • Pro Multithreading and Memory Management for iOS and OS X(Blocks Implementation)

三开财、題外篇(內(nèi)存泄露檢測工具-媽媽再也不用擔(dān)心內(nèi)存泄露)

對于ReactiveCocoa以及各種嵌套Block的常用玩家..想必僅靠Xcode的Instrument去檢測memory leak問題是絕對不夠的, 個人賣瓜推薦一個檢測內(nèi)存泄露的小工具類:
FXDeallocMonitor
拷貝FXDeallocMonitor.h芦疏、FXDeallocMonitor.m文件到項目中, 根據(jù)頭文件中的方法調(diào)用就行, 簡單易用??

對于需求更高者, 推薦近期facebook開源的FBAllocationTracker

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末区岗,一起剝皮案震驚了整個濱河市炬守,隨后出現(xiàn)的幾起案子涛救,更是在濱河造成了極大的恐慌畏邢,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件检吆,死亡現(xiàn)場離奇詭異舒萎,居然都是意外死亡,警方通過查閱死者的電腦和手機蹭沛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門臂寝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摊灭,你說我怎么就攤上這事咆贬。” “怎么了帚呼?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵掏缎,是天一觀的道長。 經(jīng)常有香客問我萝挤,道長御毅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任怜珍,我火速辦了婚禮端蛆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘酥泛。我一直安慰自己今豆,他們只是感情好嫌拣,可當(dāng)我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著呆躲,像睡著了一般异逐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上插掂,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天灰瞻,我揣著相機與錄音,去河邊找鬼辅甥。 笑死酝润,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的璃弄。 我是一名探鬼主播要销,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼夏块!你這毒婦竟也來了疏咐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤脐供,失蹤者是張志新(化名)和其女友劉穎浑塞,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體患民,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡缩举,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了匹颤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡托猩,死狀恐怖印蓖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情京腥,我是刑警寧澤赦肃,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站公浪,受9級特大地震影響他宛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜欠气,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一厅各、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧预柒,春花似錦队塘、人聲如沸袁梗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遮怜。三九已至,卻和暖如春鸿市,著一層夾襖步出監(jiān)牢的瞬間锯梁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工焰情, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陌凳,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓烙样,卻偏偏與公主長得像冯遂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谒获,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容