block本質(zhì)上也是一個(gè)OC對(duì)象,它內(nèi)部也有一個(gè)isa指針,block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對(duì)象。
Block的底層結(jié)構(gòu)
如下圖所示:

先在項(xiàng)目中定義一個(gè)block,然后執(zhí)行block,通過(guò)命令行clang -rewrite-objc main.m,將OC代碼轉(zhuǎn)化為c++代碼,看一下block的底層結(jié)構(gòu)。

現(xiàn)在通過(guò)右側(cè)的OC代碼,對(duì)照看一下c++源碼。
void(^block)(void) = ^{
NSLog(@"Hello, World!");
};
block();
//定義block
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
//執(zhí)行block內(nèi)部代碼
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
block就相當(dāng)于__main_block_impl_0;執(zhí)行block,就相當(dāng)于__block_impl->FuncPtr,找到block中封裝的函數(shù)FuncPtr,然后執(zhí)行。
Block的變量捕獲
為了保證block內(nèi)部能夠正常訪(fǎng)問(wèn)內(nèi)部的變量,block有個(gè)變量捕獲機(jī)制

auto變量存放在動(dòng)態(tài)存儲(chǔ)區(qū),隨著生命周期的結(jié)束而立即釋放。只有函數(shù)的局部變量才能定義為auto類(lèi)型。
static變量存放在靜態(tài)存儲(chǔ)區(qū),在程序整個(gè)運(yùn)行期間都不釋放。在函數(shù)內(nèi)定義的靜態(tài)變量為靜態(tài)局部變量,在函數(shù)外定義的靜態(tài)變量為靜態(tài)全局變量。
以下分別為Block中引用auto類(lèi)型局部變量,static局部變量以及全局變量,通過(guò)OC代碼編譯成c++源碼的對(duì)照

運(yùn)行結(jié)果:
Block[1635:48861] age is 10, height is 20, weight is 110
上圖可以看出age和height變量都被捕獲到block中,age是值捕獲,height是值捕獲,全部變量weight沒(méi)有被捕獲。
對(duì)象類(lèi)型的auto變量
當(dāng)block內(nèi)部訪(fǎng)問(wèn)了對(duì)象類(lèi)型的auto變量時(shí)
如果block是在棧上,將不會(huì)對(duì)auto變量產(chǎn)生強(qiáng)引用
如果block被拷貝到堆上
會(huì)調(diào)用block內(nèi)部的copy函數(shù)
copy函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_assign函數(shù)
_Block_object_assign函數(shù)會(huì)根據(jù)auto變量的修飾符(__strong、__weak、__unsafe_unretained)做出相應(yīng)的操作,形成強(qiáng)引用(retain)或者弱引用如果block從堆上移除
會(huì)調(diào)用block內(nèi)部的dispose函數(shù)
dispose函數(shù)內(nèi)部會(huì)調(diào)用_Block_object_dispose函數(shù)
_Block_object_dispose函數(shù)會(huì)自動(dòng)釋放引用的auto變量(release)