iOS-block三種類型詳解
阿新 • • 發佈:2021-06-29
Block有三種類型:__NSGlobalBlock,__NSStackBlock,__NSMallocBlock
問題:
Block有幾種型別呢?這幾種型別分別在什麼情況下出現?
我們思考一下,__NSStackBlock
在訪問外部變數時,會有什麼問題?
我們在講block的本質的時候已經知道了,block的本質就是一個 OC 物件,那麼既然它是一個 OC 物件,它就會有型別,本文就將講解block
的三種類型.並都繼承於NSBlock
我們在講block
的三種類型之前,先了解一下程式的記憶體分配情況,因為不同型別的block
分配的記憶體也不同.
- .text段 : 也稱程式碼段,我們寫的程式碼都存放在這裡
- .data區 : 也稱資料區,一般存放全域性變數, __NSGlobalBlock存放在這裡
- 堆區 : 存放我們自己
alloc
出來的物件,動態分配記憶體,需要程式設計師自己申請記憶體,自己管理. __NSMallocBlock存放在堆區 - 棧區 : 一般存放區域性變數,不需要程式設計師管理,系統自動分配,自動銷燬,__NSStackBlock存放在棧區
不同block型別的記憶體分配
一: __NSGlobalBlock
結論: 沒有訪問 auto變數 的block 就是 __NSGlobalBlock
int main(int argc, const char* argv[]) { @autoreleasepool { static int age = 10; void(^block)(void) = ^{ NSLog(@"Hello, World! %d",age); }; NSLog(@"%@",[block class]); } return 0; } 控制檯輸出:__NSGlobalBlock__
這個很好理解,不過多解釋
二: __NSStackBlock
結論:訪問了auto變數 的block 就是 __NSStackBlock
int main(int argc, const char * argv[]) { @autoreleasepool { int age = 10; void(^block)(void) = ^{ NSLog(@"Hello, World! %d",age); }; NSLog(@"%@",[block class]); } return 0; } 控制檯輸出:__NSMallocBlock__
怎麼列印的是__NSMallocBlock__
,剛才不是說訪問了auto變數
就是__NSStackBlock
嗎?
因為這裡我們使用的是ARC,在ARC環境下,Xcode編譯器再某些情況會預設幫我們做呼叫copy 變成堆block ,我們在Build Settings中把ARC設定成MRC,再來列印一下:
2018-08-30 17:37:09.846365+0800 block的型別[4318:3463149] __NSStackBlock__
這次列印的就是__NSStackBlock__
我們思考一下,__NSStackBlock
在訪問外部變數時,會有什麼問題?
會出現野指標crash 所以在ARC壞境Xcode幫我們處理成了堆block(__NSMallocBlock__)防止出現釋放了還去訪問導致野指標crash
所以,為了避免出現這種情況,我們需要把block
儲存在堆上,__NSMallocBlock
就閃亮登場了.
三: __NSMallocBlock
結論: 當一個__NSStackBlock
呼叫了copy
操作,返回的就是一個__NSMallocBlock
思考:如果我們對__NSStackBlock
進行一次 copy
操作,會發生什麼變化呢?
‼️注意
以上都是在MRC環境下
如果是在ARC環境下,編譯器會根據情況自動將棧上的block複製到堆上, 比如以下幾種情況:
-
1. block作為函式返回值時
block作為返回值編譯器會自動copy
-
2.將block賦值給__strong指標時
被強指標引用的block會自動copy
-
3.block作為Cocoa API方法名含有UsingBlock的方法引數時
UsingBlock
- 4.block作為GCD API的方法引數時
- 5.block呼叫copy方法
總結:
- 1:一共有三種類型的Block.分為
__NSGlobalBlock
,__NSStackBlock
,__NSMallocBlock
.
- 沒有訪問 auto變數 的
block
就是__NSGlobalBlock
- 訪問了auto變數 的
block
就是__NSStackBlock
- 當一個
__NSStackBlock
呼叫了copy操作,返回的就是一個__NSMallocBlock
sing
- 沒有訪問 auto變數 的
- 2:在ARC環境下,編譯器會自動把棧上的
block copy
到堆上