本文章將記錄Objective-C中Block的相關(guān)資料件缸,如有錯(cuò)誤歡迎指出~
Block的本質(zhì)
Block 實(shí)際上就是一個(gè)OC對象(結(jié)構(gòu)體中有 isa 指針),這個(gè)對象封裝了函數(shù)恰矩,以及函數(shù)執(zhí)行的上下文
Block的變量捕獲
為了保證block內(nèi)部能夠正常訪問外部的變量,block有一個(gè)變量捕獲機(jī)制。block捕獲外部變僅僅只捕獲Block閉包里面會(huì)用到的值否灾,其他用不到的值梭依,它并不會(huì)去捕獲挣柬。
局部變量
看下簡單的代碼輸出
auto int age = 10;
static int num = 25;
void (^Block)(void) = ^{
NSLog(@"age:%d,num:%d",age,num);
};
age = 20;
num = 11;
Block();
// log age = 10
age = 11
- auto變量
- auto自動(dòng)變量,離開作用域就銷毀睛挚,通常局部變量前面自動(dòng)添加auto關(guān)鍵字邪蛔。自動(dòng)變量會(huì)捕獲到block內(nèi)部,也就是說block內(nèi)部會(huì)專門新增加一個(gè)參數(shù)來存儲變量的值扎狱。 auto只存在于局部變量中侧到,訪問方式為值傳遞。
- static變量
- static 修飾的變量為指針傳遞淤击,同樣會(huì)被block捕獲匠抗。
為什么兩種變量會(huì)有這種差異呢?
因?yàn)樽詣?dòng)變量可能會(huì)銷毀污抬,block在執(zhí)行的時(shí)候有可能自動(dòng)變量已經(jīng)被銷毀了汞贸,那么此時(shí)如果再去訪問被銷毀的地址肯定會(huì)發(fā)生壞內(nèi)存訪問绳军,因此對于自動(dòng)變量一定是值傳遞而不可能是指針傳遞了。
而靜態(tài)變量不會(huì)被銷毀矢腻,所以完全可以傳遞地址门驾。而因?yàn)閭鬟f的是值得地址,所以在block調(diào)用之前修改地址中保存的值多柑,block中的地址是不會(huì)變得奶是。所以值會(huì)隨之改變。
全局變量
因?yàn)槿肿兞繜o論在哪里都可以訪問竣灌,所以block不需要捕獲全局變量
總結(jié):
局部變量都會(huì)被block捕獲聂沙,自動(dòng)變量是值捕獲,靜態(tài)變量為地址捕獲
全局變量則不會(huì)被block捕獲
Block的類型
OC中初嘹,一般Block就分為以下3種類型
-
__NSGlobalBlock__
( _NSConcreteGlobalBlock )及汉,即沒有用到外界變量或只用到全局變量、靜態(tài)變量的block屯烦。生命周期從創(chuàng)建到應(yīng)用程序結(jié)束豁生,直到程序結(jié)束才會(huì)被回收,不過我們很少使用到__NSGlobalBlock__
類型的block漫贞,因?yàn)檫@樣使用block并沒有什么意義甸箱。 -
__NSStackBlock__
( _NSConcreteStackBlock ),即只用到外部局部變量迅脐、成員屬性變量芍殖,且沒有強(qiáng)指針引用的block。__NSStackBlock__
類型的block存放在棧中谴蔑,我們知道棧中的內(nèi)存由系統(tǒng)自動(dòng)分配和釋放豌骏,作用域執(zhí)行完畢之后就會(huì)被立即釋放,而在相同的作用域中定義block并且調(diào)用block似乎也多此一舉隐锭。 -
__NSMallocBlock__
( _NSConcreteMallocBlock )窃躲,即有強(qiáng)指針引用或copy修飾的成員屬性引用的block 。存放在堆中钦睡,沒有強(qiáng)指針引用即銷毀蒂窒,需要我們自己進(jìn)行內(nèi)存管理。
Block的循環(huán)引用
這篇文章講的挺不錯(cuò)的Block 與 self 的那點(diǎn)事(iOS)
面試題
面試題請參考 這篇文章 iOS-Block相關(guān)面試題