從源碼、ARC、MRC帶你理解block的三大類型

首先,在瞭解block三大類型以前,咱們須要瞭解一個知識:c++

(舒適提醒:若是個人以前博客你沒有看,有些概念你不清楚的話,你可能很難理解,若是前面你都看了,這篇博客你看就像切菜同樣簡單!)程序員

程序的內存分配

一個由C/C++編譯的程序佔用的內存分爲如下幾個部分markdown

棧(stack):由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操做方式相似於數據結構中的棧。數據結構

堆(heap): 通常由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式相似於鏈表。iphone

全局區(靜態區static):全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另外一塊區域,程序結束後由系統釋放。函數

文字常量區:常量字符串放在這裏, 程序結束後由系統釋放測試

程序代碼區:存放函數體的二進制代碼。spa

相信你們對上面的這些內存分配的知識點都已經很是清楚,那咱們就看一下指針

block的類型

block是有3種類型,經過調用class的方法或者isa指針查看具體的類型,最終都是繼承NSBlock類型

接下來咱們就看看,block就是一個oc對象,那咱們就能夠按照oc的,直接調用class就知道它的類型了code

這裏能夠看出我前面說的,block就是oc對象,而這個NSGlobalBlock是繼承NSBlock的,其餘的種類都是繼承NSBlock,等說完了,你們能夠用這個方法試試其它2種block的的父類.

上面就是block的總共的三種類型:NSGlobalBlock、NSStackBlock、NSMallcBlock,

,這是運行時輸出的結果,其實編譯的結果可能有點不同,那咱們就把這份文件轉成c++文件,這個我以前的博客都提了不少次,此次我就不細說了(xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp)

其實你會發現,編譯之後生成的都是NSConcreteStackBlock類型,首先咱們確定以運行時爲準,由於編譯過程還有個運行,運行就會用runtime動態修改你的東西;還有其實用clang轉成c++的代碼,有時候並不必定就是最終的代碼,其實差異是不大,其實在llvm大概6.0之前都是同樣的,如今會生成一箇中間文件,還有就是程序運行中也是比較準確,若是有同窗查看源碼感受不同,不要很驚訝,這個很正常,能夠參考,差異不大.

咱們繼續看

而GlobalBlock是在數據區域,MallocBlock是在堆區,StackBlock是在棧區,我這裏不說堆、棧、數據區域的區別了,你們這個知識點若是不懂能夠去查閱一下它們的區別,否則後面的很難理解

什麼樣的類型的是GlobalBlock?什麼樣的類型是MallocBlock?什麼樣的類型是StackBlock?

先看個人總結,咱們再細細看

auto變量你們清楚吧?auto變量就是它所在的區域執行完畢,自動銷燬的變量.若是不知道請看我上一篇博客,介紹的很是清晰.接下來咱們就一個一個看每種類型的block

GlobalBlock類型

請看下面的代碼

訪問static的局部變量,全局變量a,都不是auto變量,因此上面3種狀況都是GlobalBlock,由於GlobalBlock咱們實際中用的很是少,因此這個也沒有過多的須要闡述的

StackBlock類型(重點)

按照咱們表格上面說的訪問了auto變量的block就是StackBlock,那我看一下下面的代碼:

ARC下運行的結果

應該有同窗注意,結果和咱們上面的結論不同,實際上是由於這環境是ARC,ARC下其實幫你作了不少事(這個爲何會這樣,這個內容仍是有點多,後面的博客,我會細說,你先無論這個爲何是這樣),因此咱們改爲MRC才能看到它的本質(直接把Objective-C Automatic Reference Counting 設置爲NO便可),咱們再看下面

MRC下運行的結果

這就是StackBlock類型,下面咱們再深刻看一下這個StackBlock一個特殊狀況,以下圖

MRC下運行的結果

注意到沒有,這個age的值變得很奇怪.這是由於:test()函數的做用域執行結束之後,它的做用域中的棧上面的變量就會銷燬,好比裏面的block就是StackBlock,全部test()執行完畢之後,block已經被釋放了,致使訪問內部就會出現混亂的狀況.整個block內存被釋放了裏面的全部都會出現混亂

那上面的怎麼解決這種問題呢???

答案很明顯,咱們把block棧內存變成堆內存就好了哇!怎麼變成堆block,是否是直接棧調用copy就能是堆block了,那咱們再試試:

是否是就很容易解決了!可能有同窗還有疑問,若是把GlobalBlock也來調用copy會是怎麼樣呢?這個你們能夠本身驗證,答案仍是:GlobalBlock,若是把MallocBlock也來調用copy會是怎麼樣呢?這個你們能夠本身驗證,答案仍是:引用計數加1

還有若是咱們block訪問一個對象,一個對象也是auto變量,因此也是同樣的,這些我就不驗證了,若有疑問能夠評論區討論.

MallocBlock類型

這個上面已經說的很清楚了

相信還有同窗有疑問,剛剛咱們是MRC下測試的,至於ARC爲何會是另外一個結果,我後面的博客會說到!

接下來博客我會介紹堆MallocBlock的一些具體狀況和使用,來繼續探討block

若是以爲我寫得對您有所幫助,請關注我,我會持續更新😄

相關文章
相關標籤/搜索