引言
相信大家對block
的使用都不會感到陌生, __weak
和__strong
也成為了大家解決循環(huán)引用的利器. 不過大家有否想過, block
出現(xiàn)嵌套情況時, __weak
和__strong
還能好使嗎, 或者說會不會有一些需要注意的地方呢?
正篇
首先我們定義了一個Person
類, .h
中只有1個無參無返回的block
屬性 -> personBlock
, 并且重寫了dealloc
方法, 如下圖所示:
接下來我們在主方法中創(chuàng)建一個Person
對象, 由于沒有把對象強(qiáng)引用起來, 所以對象一創(chuàng)建出來就被釋放了:
接著我們對對象進(jìn)行會造成循環(huán)引用的操作. 由于對象強(qiáng)引用著block
, block
也強(qiáng)引用著對象, 所以控制臺并沒有出現(xiàn)任何的打印, 編譯器也發(fā)出了相應(yīng)的警告:
為了解決循環(huán)引用問題, 我們請出了2大神器__weak
和__strong
, 問題當(dāng)然被迎刃而解, 這里的警告只是因?yàn)榻Y(jié)果沒被使用. 當(dāng)然了, 此處其實(shí)并不需要用到__strong
, 但實(shí)際開發(fā)中情況復(fù)雜多變, 基于普遍適用性的需求, 此處也用上__strong
:
接下來主角出場了, 如果block
中再次對block
賦值的情況下會怎么樣呢? 也就是block
嵌套. 我們可能會這樣想, strongPerson
已經(jīng)是可以放心使用的對象了, 還需要擔(dān)心什么循環(huán)引用, 直接套進(jìn)去用就行了. 真是這樣的嗎?
果然不出所料? 先別開心太早, 雖然控制臺有輸出, 對象得到了釋放, 可是你有看到編譯器已經(jīng)發(fā)出警告了嗎? 可能你覺得編譯器出毛病了, 亂警告, 其實(shí)不然, 這里是一個語法問題, 第二層block
并沒有真正被加載進(jìn)內(nèi)存. 什么? 不相信? 我只要加一句代碼問題就會馬上暴露:
只要在最后把外層的block
執(zhí)行一次, 內(nèi)層的block
才會真正地被加載進(jìn)內(nèi)存, 循環(huán)引用問題再次出現(xiàn). 出現(xiàn)循環(huán)引用的原因其實(shí)也不難理解, 因?yàn)?code>strongPerson說白了也是一個強(qiáng)引用, 它與一般強(qiáng)引用的區(qū)別在于, 它只會在被定義的block
中對對象進(jìn)行強(qiáng)引用, 在block
過后就會把對象釋放掉, 所以在第2層block
中繼續(xù)用strongPerson
出現(xiàn)循環(huán)引用跟一般造成循環(huán)引用的原因其實(shí)是一樣的, 解決方法也是如出一轍, 而且可以繼續(xù)嵌套下去, 此處的警告同樣是結(jié)果沒被使用:
補(bǔ)充
另外想補(bǔ)充一個關(guān)于block
強(qiáng)引用對象的問題, 之前在網(wǎng)上看到過一些說法, 大概就是block
會對內(nèi)部所有的對象產(chǎn)生一個強(qiáng)引用, 比如說:
self.block = ^{
self.name = @"Veeco";
};
這里block
首先對self
產(chǎn)生一個強(qiáng)引用, 其實(shí)還對name
這個屬性產(chǎn)生了一個強(qiáng)引用, 在這個補(bǔ)充里, 我就是想要澄清關(guān)于這個name
屬性被強(qiáng)引用的問題.
首先我們在剛才代碼的基礎(chǔ)上加一個Dog
類, 只重寫其中的dealloc
方法:
接著在Person
類.h
中增加一個Dog
屬性 -> dog
, 需要注意的是此處用的是weak
關(guān)鍵字:
正篇開始, 我們在主方法中分別創(chuàng)建person
和dog
對象, 并把dog
對象賦值給person
對象的dog
屬性, 接著在person
對象的block
屬性中訪問person
對象的dog
屬性, 按照網(wǎng)上的說法, 如果block
強(qiáng)引用著person
對象的dog
屬性的話, 我們是看不到Dog dealloc
打印的, 接下來就來見證奇跡的時刻:
結(jié)果出來了, Person
類沒被釋放這是肯定的, 因?yàn)樵斐闪搜h(huán)引用, 不過我們看到了Dog dealloc
打印, 也就是說block
并沒有強(qiáng)引用著person
對象中的dog
屬性, 它只強(qiáng)引用著person
對象.