一 明確兩點(diǎn)
1,Block可以訪問Block函數(shù)以及語法作用域以內(nèi)的外部變量。也就是說:一個函數(shù)里定義了個block,這個block可以訪問該函數(shù)的內(nèi)部變量(當(dāng)然還包括靜態(tài),全局變量)-即block可以使用和本身定義范圍相同的變量。
2,Block其實(shí)是特殊的Objective-C對象,可以使用copy,release等來管理內(nèi)存,但和一般的NSObject的管理方式有些不同,稍后會說明。
三
根據(jù)Block中是否引用了自動變量,可以將Block存儲區(qū)域分類:
1,_NSConcreteStackBlock-存儲在棧上
2,_NSConcreteGlobalBlock-存儲在全局?jǐn)?shù)據(jù)區(qū)域(和全局變量一樣)
3,_NSConcreteMallocBlock-存儲在堆上
沒有引用自動變量或者在全局作用域的Block為_NSConcreteGlobalBlock,其他的基本上都是_NSConcreteStackBlock。
對_NSConcreteStackBlock執(zhí)行copy操作會生成_NSConcreteMallocBlock。
一般來說出問題的Block大部分都是_NSConcreteStackBlock,超過了_NSConcreteStackBlock的作用域_NSConcreteStackBlock就會銷毀。
四,
對Block執(zhí)行retain,copy方法的效果Block是C語言的擴(kuò)展,C語法也可以使用Block的語法,對應(yīng)的C語言使用Block_copy,Block_release.
無論是_NSConcreteStackBlock,還是_NSConcreteGlobalBlock,執(zhí)行retain都不起作用。而_NSConcreteMallocBlock執(zhí)行retain引用計數(shù)+1。
對于copy操作,_NSConcreteStackBlock會被復(fù)制到堆上得到新的_NSConcreteMallocBlock,而_NSConcreteGlobalBlock執(zhí)行copy操作不起作用。而對_NSConcreteMallocBlock執(zhí)行copy操作會引起引用計數(shù)加1。
那么就引出一個問題,對_NSConcreteMallocBlock多次copy會不會引起問題呢?參考Objective-C高級管理115頁。
五,什么時候要對NSConcreteStackBlock執(zhí)行copy操作?
配置在棧上的Block也就是NSConcreteStackBlock類型的Block,如果其所屬的變量作用域結(jié)束該Block就會廢棄。這個時候如果繼續(xù)使用該Block,就應(yīng)該使用copy方法,將NSConcreteStackBlock拷貝為_NSConcreteMallocBlock。
當(dāng)_NSConcreteMallocBlock的引用計數(shù)變?yōu)?,該_NSConcreteMallocBlock就會被釋放。
如果是非ARC環(huán)境,需要顯式的執(zhí)行copy或者antorelease方法。
而當(dāng)ARC有效的時候,實(shí)際上大部分情況下編譯器已經(jīng)為我們做好了,自動的將Block從棧上復(fù)制到堆上。包括以下幾個情況:
1,Block作為返回值時類似在非ARC的時候,對返回值Block執(zhí)行[[returnedBlock copy] autorelease];
2,方法的參數(shù)中傳遞Block時
3,Cocoa框架中方法名中還有useringBlock等時
4,GCD相關(guān)的一系列API傳遞Block時。
比如:[mutableAarry addObject:stackBlock];這段代碼在非ARC環(huán)境下肯定有問題,而在ARC環(huán)境下方法參數(shù)中傳遞NSConcreteStackBlock會自動執(zhí)行copy。
七,演示代碼主要為了說明在ARC和非ARC環(huán)境下使用Block的一些區(qū)別。這里還是給出CococChina上的兩個典型例子說明:
//Test1
void exampleB_addBlockToArray(NSMutableArray *array) {
char b = 'B';
[array addObject:^{
printf("%c\n", b);
}];
}
void exampleB() {
NSMutableArray *array = [NSMutableArray array];
exampleB_addBlockToArray(array);
void (^block)() = [array objectAtIndex:0];
block();
}
//Test2
void exampleC_addBlockToArray(NSMutableArray *array) {
[array addObject:^{
printf("C\n");
}];
}
void exampleC() {
NSMutableArray *array = [NSMutableArray array];
exampleC_addBlockToArray(array);
void (^block)() = [array objectAtIndex:0];
block();
}
//Test3
typedef void (^dBlock)();
dBlock exampleD_getBlock() {
char d = 'D';
return ^{
printf("%c\n", d);
};
}
void exampleD() {
exampleD_getBlock()();
}
Test1:exampleB_addBlockToArray添加的Block為NSConcreteStackBlock,在非ARC環(huán)境下,執(zhí)行該Block時,棧上的數(shù)據(jù)已經(jīng)被清除了,錯誤。而在ARC環(huán)境下,作為參數(shù)的Block會自動copy,不會出現(xiàn)問題;對應(yīng)是五(2)情況。
Test2:exampleC_addBlockToArray添加的Block為_NSConcreteGlobalBlock,存儲在程序的數(shù)據(jù)區(qū),相當(dāng)于一個不使用外部環(huán)境的函數(shù),沒有用到棧上的數(shù)據(jù),所有無論是ARC還是非ARC都能正常執(zhí)行。
Test3ARC中作為返回值的NSConcreteStackBlock會被執(zhí)行copy操作。所有ARC運(yùn)行正常,非ARC錯誤。對應(yīng)是五(1)情況。
轉(zhuǎn)載地址:http://www.tekuba.net/program/349/