我所理解的Block:3、Block的存儲(chǔ)區(qū)域

23、在前文中的例子中,Block結(jié)構(gòu)體里的isa指針還沒(méi)有詳細(xì)講解,這個(gè)指針都被置向了_NSConcreteStackBlock,它標(biāo)識(shí)了Block的類(lèi)型。
其實(shí)除了_NSConcreteStackBlock這個(gè)類(lèi)型外,Block還有其他的類(lèi)型,這些類(lèi)型總共有3種:
(1)、_NSConcreteStackBlock
(2)、_NSConcreteMallocBlock
(3)、_NSConcreteGlobalBlock

24、這3種類(lèi)型分別表示了Block對(duì)象存儲(chǔ)的區(qū)域,如下圖:


25、編譯器的模式也會(huì)影響到Block對(duì)象的存儲(chǔ),同一個(gè)Block對(duì)象在ARC模式下和在MRC模式下可能會(huì)存儲(chǔ)在不同的區(qū)域。接下來(lái),就使用代碼來(lái)研究一下在ARC模式下和在MRC模式下,全局Block、普通Block、截獲變量的Block和截獲可變變量的Block分別是怎么存儲(chǔ)的。

26、可以通過(guò)打印出Block對(duì)象來(lái)確定它存儲(chǔ)的位置,這3種類(lèi)型的Block對(duì)象打印出來(lái)的類(lèi)分別是:
(1)、__NSStackBlock__
(2)、__NSMallocBlock__
(3)、__NSGlobalBlock__

普通全局Block

27、首先在ARC模式下,編寫(xiě)一個(gè)全局普通Block,并分別打印出持有這個(gè)Block對(duì)象的變量,和這個(gè)變量的復(fù)制值:



可以發(fā)現(xiàn),兩種情況下打印出來(lái)的Block對(duì)象都是__NSGlobalBlock__類(lèi)的,說(shuō)明它們都存儲(chǔ)在.data區(qū)。

28、試一下在MRC模式下執(zhí)行相同的代碼:



發(fā)現(xiàn)效果相同。說(shuō)明,<b>普通全局Block在ARC模式下和MRC模式下的存儲(chǔ)區(qū)域是一樣的,都是.data區(qū)。</b>

截獲變量的全局Block

29、全局Block能截獲的變量,只能是全局變量(不可能獲取到局部變量)。而全局變量在Block中本身就是可變的了,所以“截獲變量的全局Block”就相當(dāng)于“截獲可變?nèi)肿兞康娜諦lock”。

30、編寫(xiě)以下代碼,在ARC模式下執(zhí)行:



在MRC模式下也執(zhí)行相同代碼:



從執(zhí)行結(jié)果可以看出,截獲了變量的全局Block存儲(chǔ)區(qū)域和普通全局Block是一樣的。這說(shuō)明了,<b>全局Block都是__NSGlobalBlock__類(lèi)的,存儲(chǔ)在.data區(qū)。</b>

普通Block

31、對(duì)于普通Block,編寫(xiě)以下代碼來(lái)查看它的存儲(chǔ)區(qū)域,在ARC模式下分別打印出持有普通Block的變量、持有普通Block的變量的復(fù)制值、普通Block對(duì)象和普通Block對(duì)象的復(fù)制值:



再在MRC模式下也執(zhí)行相同代碼:



從打印結(jié)果可以看出:<b>不論是在ARC模式下還是在MRC模式下,不截獲變量的普通Block都是當(dāng)作__NSGlobalBlock__類(lèi)對(duì)象處理的,存儲(chǔ)在.data區(qū)。</b>
還有一點(diǎn)需要注意:前文在使用clang命令轉(zhuǎn)換普通Block的時(shí)候,Block對(duì)象的isa指針是指向_NSConcreteStackBlock的,說(shuō)明普通Block本質(zhì)上是__NSStackBlock__類(lèi)的;而在此處通過(guò)打印可知,因?yàn)闆](méi)有截獲變量,編譯器實(shí)際上就將普通Block當(dāng)做__NSGlobalBlock__類(lèi)來(lái)處理了。

截獲變量的Block

32、上文演示的幾種Block在不同編譯器模式下存儲(chǔ)區(qū)域并沒(méi)有差別,接下來(lái)的Block就開(kāi)始有差別了。
編寫(xiě)以下代碼,在ARC模式下分別打印出持有截獲變量Block的變量、持有截獲變量Block的變量的復(fù)制值、截獲變量的Block對(duì)象和截獲變量的Block對(duì)象的復(fù)制值:



然后在MRC模式下執(zhí)行相同代碼,查看結(jié)果:



比較兩種模式下的打印結(jié)果,可以發(fā)現(xiàn):
(1)、在MRC模式下,截獲變量的Block對(duì)象本身是存儲(chǔ)在棧上的,即使通過(guò)持有這個(gè)Block對(duì)象的變量來(lái)訪問(wèn)它,仍然能順利訪問(wèn)到存儲(chǔ)在棧上的Block對(duì)象。只有主動(dòng)調(diào)用copy方法,才能將Block對(duì)象從棧上復(fù)制到堆上;
(2)、在ARC模式下,截獲變量的Block對(duì)象本身也是存儲(chǔ)在棧上的,只是當(dāng)使用持有這個(gè)Block對(duì)象的變量來(lái)訪問(wèn)它時(shí),這個(gè)Block對(duì)象就會(huì)被從棧上復(fù)制到堆上,這樣變量訪問(wèn)到的就是存儲(chǔ)在堆上的Block對(duì)象了。如果主動(dòng)調(diào)用copy方法,Block對(duì)象也會(huì)被賦值在堆上;

(3)、比較兩種模式下的區(qū)別,可以發(fā)現(xiàn)在使用變量訪問(wèn)Block對(duì)象的情況下,在不同編譯器模式下Block對(duì)象的存儲(chǔ)區(qū)域是不同的。所以才會(huì)有ARC模式下沒(méi)有_NSConcreteStackBlock這種說(shuō)法。

截獲可變變量的Block
33、再來(lái)看一看最后一種Block,編寫(xiě)以下代碼,在ARC模式下分別打印出持有截獲可變變量Block的變量、持有截獲可變變量Block的變量的復(fù)制值、截獲可變變量的Block對(duì)象和截獲可變變量的Block對(duì)象的復(fù)制值:



然后在MRC模式下執(zhí)行相同代碼,查看結(jié)果:



可以發(fā)現(xiàn),情況和截獲變量的Block一樣,都是在使用變量訪問(wèn)Block對(duì)象的情況下,在不同編譯器模式下Block對(duì)象的存儲(chǔ)區(qū)域不同。那么可以得出以下結(jié)論:
(1)、<b>在不同編譯器模式下,截獲變量的Block本身都是存儲(chǔ)在棧上的;</b>
(2)、<b>使用變量訪問(wèn)這種Block時(shí),MRC模式下能訪問(wèn)到棧上的對(duì)象,ARC模式下訪問(wèn)到的是被復(fù)制到堆上的對(duì)象。</b>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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