iOS ? block循環(huán)引用

請耐心把這篇文章看完匹层,你對 Block 會有更深刻的了解。

這里直接用一個需求來探究循環(huán)引用的問題:如果我想在Block中延時來運行某段代碼,這里就會出現(xiàn)一個問題忽刽,看這段代碼:

- (void)viewDidLoad {

?[super viewDidLoad];

?MitPerson*person = [[MitPerson alloc]init];

?__weak MitPerson * weakPerson = person;

?person.mitBlock = ^{

? ? ?dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

? ? ? ? ?[weakPerson test];

? ? ?});

?};

?person.mitBlock();

}

直接運行這段代碼會發(fā)現(xiàn)[weakPerson test];并沒有執(zhí)行,打印一下會發(fā)現(xiàn)夺欲,weakPerson 已經(jīng)是 Nil 了跪帝,這是由于當我們的 viewDidLoad 方法運行結(jié)束,由于是局部變量些阅,無論是 MitPerson 和 weakPerson 都會被釋放掉伞剑,那么這個時候在 Block 中就無法拿到正真的 person 內(nèi)容了。

按如下方法修改代碼:

- (void)viewDidLoad {

?[super viewDidLoad];

?MitPerson*person = [[MitPerson alloc]init];

?__weak MitPerson * weakPerson = person;

?person.mitBlock = ^{

? ? ?__strong MitPerson * strongPerson = weakPerson;

? ? ?dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

? ? ? ? ?[strongPerson test];

? ? ?});

?};

?person.mitBlock();

}

這樣當2秒過后市埋,計時器依然能夠拿到想要的 person 對象黎泣。

二、深入探究原理

這里將會對每行代碼逐步進行說明

1缤谎、開辟一段控件存儲 person 類對象內(nèi)容抒倚,創(chuàng)建 person 強指針。

MitPerson*person = [[MitPerson alloc]init];

2弓千、創(chuàng)建一個弱指針 weakPerson 指向person對象內(nèi)容

__weak MitPerson * weakPerson = person;

person.mitBlock = ^{

3衡便、在 person 對象的 Block 內(nèi)部創(chuàng)建一個強指針來指向 person 對象,為了保證當計時器執(zhí)行代碼的時候洋访,person 對象沒有被系統(tǒng)銷毀所以我們必須在系統(tǒng)內(nèi)部進行一次強引用镣陕,并用 GCD 計時器引用 strongPerson,為了保留 person 對象姻政,在下面會對這里更加詳細的說明呆抑。

__strong MitPerson * strongPerson = weakPerson;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

[strongPerson test];

});

};

4、執(zhí)行 Block 代碼

person.mitBlock();

下面將詳細分析一下下面這段代碼:

person.mitBlock = ^{

__strong MitPerson * strongPerson = weakPerson;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

[strongPerson test];

});

};

首先需要明白一些關(guān)于 Block 的概念:

1汁展、默認情況下鹊碍,block 是放在棧里面的

2、一旦blcok進行了copy操作食绿,block的內(nèi)存就會被放在堆里面

3侈咕、堆立面的block(被copy過的block)有以下現(xiàn)象

1> block內(nèi)部如果通過外面聲明的強引用來使用,那么block內(nèi)部會自動產(chǎn)生一個強引用指向所使用的對象器紧。

2> block內(nèi)部如果通過外面聲明的弱引用來使用耀销,那么block內(nèi)部會自動產(chǎn)生一個弱引用指向所使用的對象。

我們進行這段代碼的目的:

首先铲汪,我們需要在 Block 塊中調(diào)用熊尉,person 對象的方法罐柳,既然是在 Block 塊中我們就應該使用弱指針來引用外部變量,以此來避免循環(huán)引用狰住。但是又會出現(xiàn)問題张吉,什么問題呢?就是當我計時器要執(zhí)行方法的時候催植,發(fā)現(xiàn)對象已經(jīng)被釋放了肮蛹。

接下來就是為了避免 person 對象在計時器執(zhí)行的時候被釋放掉:那么為什么 person 對象會被釋放掉呢?因為無論我們的person強指針還是 weakPerson 弱指針都是局部變量查邢,當執(zhí)行完ViewDidLoad 的時候蔗崎,指針會被銷毀酵幕。對象只有被強指針引用的時候才不會被銷毀扰藕,而我們?nèi)绻苯右猛獠康膹娭羔槍ο笥謺a(chǎn)生循環(huán)引用,這個時候我們就用了一個巧妙的代碼來完成這個需求芳撒。

首先在 person.mitBlock 引用外部 weakPerson邓深,并在內(nèi)部創(chuàng)建一個強指針去指向 person 對象,因為在內(nèi)部聲明變量笔刹,Block 是不會強引用這個對象的芥备,這也就在避免的 person.mitBlock 循環(huán)引用風險的同時,又創(chuàng)建出了一個強指針指向?qū)ο蟆?/p>

之后再用 GCD 延時器 Block 來引用相對于它來說是外部的變量 strongPerson 舌菜,這時延時器 Block 會默認創(chuàng)建出來一個強引用來引用 person 對象萌壳,當 person.mitBlock 作用域結(jié)束之后 strongPerson 會跟著被銷毀,內(nèi)存中就僅剩下了 延時器 Block 強引用著 person 對象日月,2秒之后觸發(fā) test 方法袱瓮,GCD Block 內(nèi)部方法執(zhí)行完畢之后,延時器和對象都被銷毀爱咬,這樣就完美實現(xiàn)了我們的需求尺借。

最后再用一張圖來闡述各個指針、Block 與對象之間的關(guān)系

黑色代表強引用精拟,綠色代表弱引用

總結(jié):person.mitBlock 中創(chuàng)建 strongPerson 是為了能夠使 GCD Block 保存 person 對象燎斩,創(chuàng)建 strongPerson 時候使用 weakPerson 是為了避免 mitBlock 直接引用外部強指針變量所造成的循環(huán)引用。

Block循環(huán)引用.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜂绎,一起剝皮案震驚了整個濱河市栅表,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌师枣,老刑警劉巖怪瓶,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坛吁,居然都是意外死亡劳殖,警方通過查閱死者的電腦和手機铐尚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哆姻,“玉大人宣增,你說我怎么就攤上這事∶В” “怎么了爹脾?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長箕昭。 經(jīng)常有香客問我坛怪,道長宰闰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮义锥,結(jié)果婚禮上控汉,老公的妹妹穿的比我還像新娘心铃。我一直安慰自己译断,他們只是感情好,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布积暖。 她就那樣靜靜地躺著藤为,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夺刑。 梳的紋絲不亂的頭發(fā)上缅疟,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音遍愿,去河邊找鬼存淫。 笑死,一個胖子當著我的面吹牛错览,可吹牛的內(nèi)容都是我干的纫雁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼倾哺,長吁一口氣:“原來是場噩夢啊……” “哼轧邪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起羞海,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤忌愚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后却邓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體硕糊,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了简十。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片檬某。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖螟蝙,靈堂內(nèi)的尸體忽然破棺而出恢恼,到底是詐尸還是另有隱情,我是刑警寧澤胰默,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布场斑,位于F島的核電站,受9級特大地震影響牵署,放射性物質(zhì)發(fā)生泄漏漏隐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一奴迅、第九天 我趴在偏房一處隱蔽的房頂上張望青责。 院中可真熱鬧,春花似錦半沽、人聲如沸爽柒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至做葵,卻和暖如春占哟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酿矢。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工榨乎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瘫筐。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓蜜暑,卻偏偏與公主長得像,于是被迫代替她去往敵國和親策肝。 傳聞我的和親對象是個殘疾皇子肛捍,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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