Block簡介 Block其實包含兩個部分內容 Block執行的代碼,這是在編譯的時候已經生成好的; 一個包含Block執行時需要的所有外部變數值的數據結構。 Block將使用到的、作用域附近到的變數的值建立一份快照拷貝到棧上。 Block與函數另一個不同是,Block類似ObjC的對象,可以使用自
Block簡介
Block其實包含兩個部分內容
- Block執行的代碼,這是在編譯的時候已經生成好的;
- 一個包含
Block執行時需要的所有外部變數值
的數據結構。 Block將使用到的、作用域附近到的變數的值
建立一份快照拷貝到棧上。 - Block與函數另一個不同是,Block類似ObjC的對象,可以使用自動釋放池管理記憶體
Block在記憶體中的位置
根據Block在記憶體中的位置分為三種類型NSGlobalBlock,NSStackBlock, NSMallocBlock。
- NSGlobalBlock:類似函數,位於text段;
- NSStackBlock:位於棧記憶體,函數返回後Block將無效;
- NSMallocBlock:位於堆記憶體。
Block被另一個Block使用時,另一個Block被copy到堆上時,被使用的Block也會被copy。但作為參數的Block是不會發生copy的。
Block對不同類型的變數的存取
基本類型
適用於MRC和ARC的情況
- 局部自動變數,在Block中只讀。Block定義時copy變數的值,在Block中作為常量使用,所以即使變數的值在Block外改變,也不影響他在Block中的值。
- static變數、全局變數。Block就可以對它們進行讀寫了。因為全局變數或靜態變數在記憶體中的地址是固定的,Block在讀取該變數值的時候是直接從其所在記憶體讀出,獲取到的是最新值,而不是在定義時copy的常量。
- Block變數,被
__block
修飾的變數稱作Block變數。 基本類型的Block變數等效於全局變數、或靜態變數。
ObjC對象
不同於基本類型,Block會引起對象的引用計數變化。
MRC:
- 局部自動變數,在Block copy時,系統自動retain對象,增加其引用計數。
- static變數,全局變數,在記憶體中的位置是確定的,所以Block copy時不會retain對象。
- Block變數,在Block copy時也不會retain。
- 實例變數,在Block copy時也沒有直接retain 實例變數對象本身,但會retain 實例變數的擁有者self。所以在Block中可以直接讀寫 實例變數。
ARC:
- 只有在使用local變數時,block會複製指針,且強引用指針指向的對象一次。其它如全局變數、static變數等,block不會拷貝指針,只會強引用指針指向的對象一次。
__block變數,在Block copy時
會retain__block變數-
struct __Block_byref_intValue_0 { void *__isa; __Block_byref_intValue_0 *__forwarding; int __flags; int __size; int intValue; }; struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc; __Block_byref_intValue_0 *intValue; // by ref __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_intValue_0 *_intValue, int flags=0) : intValue(_intValue->__forwarding) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; } };
-
- 標記了為__weak或__unsafe_unretained的local變數。block仍會強引用指針對象一次。
參考:http://my.oschina.net/u/1432769/blog/390401?fromerr=QO9ABGMC
http://tanqisen.github.io/blog/2013/04/19/gcd-block-cycle-retain/