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
到堆上