block詳解<3>: block在內(nèi)存區(qū)域中是如何分布的

如果大家還有映像的話,我們在前面講解結(jié)構(gòu)體 _block_impl的時候,里面有一個成員叫isa,這個代表了block在內(nèi)存區(qū)域中的分布。如果你看了一些關(guān)于block的文章,isa會有三種取值:

isa = &_NSConcreteStackBlock;
isa = &_NSConcreteMallocBlock;
isa = &_NSConcreteGlobalBlock;

但是clang出來的文件,里面都是第一種,說明這并不是block在內(nèi)存中的真正分布。真正的分布,我們可以通過打印來確定。


屏幕快照 2016-09-22 2.35.54 PM.png
屏幕快照 2016-09-22 2.49.47 PM.png

第二張圖的打印結(jié)果是NSMallocBlock,同時我又試了其他的幾種情況,發(fā)現(xiàn)都是NSMallocBlock,說明在ARC環(huán)境下,棧上的block默認(rèn)都會被拷貝到堆上,也就是說,在ARC環(huán)境下,block只有兩種類型:NSGlobalBlock 和 NSMallocBlock。那么到底有沒有特殊的情況呢?后來查查資料,發(fā)現(xiàn)還真有。

屏幕快照 2016-09-22 5.09.57 PM.png

執(zhí)行上面的代碼的時候,直接crash了,從錯誤的提示可以看出,是某個東西的內(nèi)存過早的釋放了。我們仔細(xì)觀察一下控制臺,發(fā)現(xiàn)數(shù)組的第一個元素是NSMallocBlock類型,這是被分配在堆上的block;數(shù)組的第二個元素有點兒問題:發(fā)現(xiàn)它的內(nèi)存地址跟argv的格式比較像,而argv是函數(shù)的參數(shù),內(nèi)存是被分配在棧內(nèi)存上的,所以第二個block也是被分配在棧內(nèi)存上的,并沒有被拷貝到堆內(nèi)存上。然后我們換一種寫法:

屏幕快照 2016-09-22 5.21.23 PM.png

發(fā)現(xiàn)可以正常運行,并且打印的結(jié)果也是我們想要的。

我們再看一下上面的數(shù)組的初始化函數(shù)

+ (instancetype)arrayWithObjects:(ObjectType)firstObj, ... NS_REQUIRES_NIL_TERMINATION;

這個函數(shù)是一個可變函數(shù),只有第一個參數(shù)被顯示的申明為ObjectType類型,也就是id類型,其他的參數(shù)并沒有被顯示的申明為id類型。這也驗證了第一種情況下第一個block被分配在堆上,第二個block被分配在棧上。而我們的第二種寫法是,先申明一下block,在block到底是什么一文中,我們已經(jīng)說了,block其實就是一個函數(shù)指針,也可以說它是一個id類型,所以在第二種寫法下,兩個block都被顯示的申明為id類型,所以都被分配在堆上,所以第二種情況沒有問題。

由此我們可以得出一個結(jié)論:block作為函數(shù)的參數(shù)時,一定要被顯示的申明為id類型,才會被分配在堆上。
參考文章

ARC 下向 NSArray 添加 Block 元素的一個小坑

最后編輯于
?著作權(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)容