Blocks編程要點
目錄
簡介................................................................................................................................................................... 1本文檔結(jié)構(gòu)............................................................................................................................ 1
第一章BLOCKS入門............................................................................................................................. 2
1.1聲明和使用一個BLOCK............................................................................................ 2
1.2直接使用BLOCK........................................................................................................ 3
1.3 ?COCOA的BLOCKS...................................................................................................... 3
1.4 ?__BLOCK變量............................................................................................................. 4
第二章 概念概述...................................................................................................................................... 7
2.1 ?BLOCK功能................................................................................................................ 7
2.2用處............................................................................................................................ 7
第三章 聲明和創(chuàng)建BLOCKS.................................................................................................................. 8
3.1聲明一個BLOCK的引用............................................................................................. 8
3.2創(chuàng)建一個BLOCK......................................................................................................... 8
3.3全局BLOCKS............................................................................................................... 9
第四章BLOCKS和變量....................................................................................................................... 10
4.1變量類型.................................................................................................................. 10
4.2 ?__BLOCK存儲類型................................................................................................... 11
4.3對象(OBJECT)和BLOCK變量................................................................................... 13
4.3.1 ?Objective-C對象........................................................................................... 13
4.3.2 ?C++對象........................................................................................................ 13
4.3.3 ?Blocks............................................................................................................ 14
第五章 使用BLOCKS ........................................................................................................................... 15
5.1調(diào)用一個BLOCK...................................................................................................... 15
5.2使用BLOCK作為函數(shù)的參數(shù).................................................................................. 15
5.3使用BLOCK作為方法的參數(shù).................................................................................. 16
5.4拷貝BLOCKS............................................................................................................ 18
5.5需要避免的模式...................................................................................................... 18
5.6調(diào)試.......................................................................................................................... 19
結(jié)束語............................................................................................................................................................. 20推薦資源......................................................................................................................................................... 21
簡介
Block對象是 C 級別的語法和運行時特性。它們和標準 C 函數(shù)很類似,但是除了
可執(zhí)行代碼外,它們還可能包含了變量自動綁定(棧)或內(nèi)存托管(堆)。所以一個block維護一個狀態(tài)集(數(shù)據(jù)),它們可以在執(zhí)行的時候用來影響程序行為。
你可以用blocks來編寫函數(shù)表達式,這些表達式可以作為 API 使用,或可選的存
儲,或被多個線程使用。Blocks作為回調(diào)特別有用,因為block攜帶了進行回調(diào)所需
要的執(zhí)行代碼和執(zhí)行過程中需要的數(shù)據(jù)。
Blocks在GCC和Clang里面可用,它附帶在 Mac OS X v10.6 里面的Xcode開發(fā)
工具里面。你可以在 Mac OS X v10.6 及其之后,和 iOS 4.0 及其之后上面使用blocks。Blocks運行時是開源的,你可以在 LLVM’s compiler-rt subproject repository
(LLVM 的 RT 編譯器的子項目庫)里面找到它。Blocks同樣作為標準 C 工作組出現(xiàn)在
N1370:Apple’s Extensions to C(該文檔同樣包括了垃圾回收機制)。因為Objective-C和C++都是從 C 發(fā)展而來,blocks被設(shè)計在三種語言上面使用(也包括Objective-C++)。(語法反應(yīng)了這一目標)
你應(yīng)該閱讀該文檔來掌握block對象是什么和如何在C,C++或Objective-C上面使
用它們來讓你的程序更高效和更易于維護。
本文檔結(jié)構(gòu)
該文檔包含了以下幾個章節(jié):
“Blocks入門”提供了一個對blocks的快速的和實際的介紹。
“概念概述”提供了對blocks概念的介紹。
“聲明和創(chuàng)建Blocks”描述如何聲明block變量,并實現(xiàn)該blocks。
“Blocks和變量”介紹了blocks和變量的交互,并定義__block存儲類型修飾
符。
“使用Blocks”說明不同的使用模式。
Blocks Programming Topics
第一章Blocks入門以下部分使用實際的例子幫助你開始使用Blocks。
1.1聲明和使用一個Block
使用^操作符來來聲明一個block變量和指示block文本的開始。Block本身的主
體被{}包含著,如下面的例子那樣(通常使用 C 的;符合指示block的結(jié)束):
該示例的解析如下圖:
int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
注意block可以使用相同作用域范圍內(nèi)定義的變量。
如果你聲明一個block作為變量,你可以把它簡單的作為一個函數(shù)使用:
int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
printf("%d", myBlock(3));
// prints "21"
Blocks Programming Topics
1.2直接使用Block
在很多情況下,你不需要聲明一個block變量;相反你可以簡單的寫一個內(nèi)聯(lián)
(inline)的block文本,它需要作為一個參數(shù)使用。以下的代碼使用qsort_b函數(shù)。qsort_b和標準qsort_r函數(shù)類似,但是它使用block作為最后一個參數(shù)。
char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" };
qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {
char *left = *(char **)l;
char *right = *(char **)r;
return strncmp(left, right, 1);
});
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
1.3 Cocoa的Blocks
在Cocoa frameworks里面有部分方法使用block作為參數(shù),通常不是執(zhí)行一個對
象的集合操作,就是在操作完成的時候作為回調(diào)使用。下面的例子顯示了如何通過NSArray的方法sortedArrayUsingComparator:使用block。該方法使用一個參數(shù),即block。為了舉例說明,該情況下block被定義為NSComparator的局部變量:
NSArray *stringsArray = [NSArray arrayWithObjects:
@"string 1",
@"String 21",
@"string 12",
@"String 11",
@"String 02", nil];
static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch
|
NSWidthInsensitiveSearch | NSForcedOrderingSearch;
NSLocale *currentLocale = [NSLocale currentLocale];
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[3]
Blocks Programming Topics
NSComparator finderSortBlock = ^(id string1, id string2) {
NSRange string1Range = NSMakeRange(0, [string1 length]);
return [string1 compare:string2 options:comparisonOptions range:string1Range
locale:currentLocale];
};
NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock];
NSLog(@"finderSortArray: %@", finderSortArray);
/*
Output:
finderSortArray: (
"string 1",
"String 02",
"String 11",
"string 12",
"String 21"
)
*/
1.4 __block變量
Blocks的最大一個特色就是可以修改相同作用域的變量。你可以使用__block存
儲類型修飾符來給出信號要修改一個變量。改編“Cocoa的Blocks”所示的例子,你
可以使用一個block來計數(shù)多少個字符串和block中只讀變量currentLocal相同:
NSArray *stringsArray = [NSArray arrayWithObjects:
@"string 1",
@"String 21", // <-
@"string 12",
@"String 11",
@"Stri?ng 21", // <-
@"Strin?g 21", // <-
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[4]
Blocks Programming Topics
@"String 02", nil];
NSLocale *currentLocale = [NSLocale currentLocale];
__block NSUInteger orderedSameCount = 0;
NSArray *diacriticInsensitiveSortArray = [stringsArray sortedArrayUsingComparator:^(id
string1, id string2) {
NSRange string1Range = NSMakeRange(0, [string1 length]);
NSComparisonResult comparisonResult = [string1 compare:string2
options:NSDiacriticInsensitiveSearch range:string1Range locale:currentLocale];
if (comparisonResult == NSOrderedSame) {
orderedSameCount++;
}
return comparisonResult;
}];
NSLog(@"diacriticInsensitiveSortArray: %@", diacriticInsensitiveSortArray);
NSLog(@"orderedSameCount: %d", orderedSameCount);
/*
Output:
diacriticInsensitiveSortArray: (
"String 02",
"string 1",
"String 11",
"string 12",
"String 21",
"Str\U00eeng 21",
"Stri\U00f1g 21"
)
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[5]
Blocks Programming Topics
orderedSameCount: 2
*/
這會在“Blocks和變量”部分里面有更多的討論。
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[6]
Blocks Programming Topics
第二章 概念概述
Block對象提供了一個使用 C 語言和 C 派生語言(如Objective-C和C++)來創(chuàng)建
表達式作為一個特別(ad hoc)的函數(shù)。在其他語言和環(huán)境中,一個block對象有時候
被成為“閉包(closure)”。在這里,它們通常被口語化為”塊(blocks)”,除非在某
些范圍它們?nèi)菀缀蜆藴?C 表達式的塊代碼混淆。
2.1 Block功能
一個block就是一個匿名的內(nèi)聯(lián)代碼集合體:
和函數(shù)一樣擁有參數(shù)類型
有推斷和聲明的返回類型
可以捕獲它的聲明所在相同作用域的狀態(tài)
可以和其他定義在相同作用域范圍的blocks進行共享更改
在相同作用域范圍(棧幀)被銷毀后持續(xù)共享和更改相同作用域范圍(棧幀)的狀
態(tài)
你可以拷貝一個block,甚至可以把它作為可執(zhí)行路徑傳遞給其他線程(或者在自
己的線程內(nèi)傳遞給run loop)。編譯器和運行時會在整個block生命周期里面為所有block引用變量保留一個副本。盡管blocks在純 C 和 C++上面可用,但是一個block也同樣是一個Objective-C的對象。
2.2用處
Blocks通常代表一個很小、自包的代碼片段。因此它們作為封裝的工作單元在并
發(fā)執(zhí)行,或在一個集合項上,或當其他操作完成時的回調(diào)的時候非常實用。
Blocks作為傳統(tǒng)回調(diào)函數(shù)的一個實用的替代辦法,有以下兩個原因:
它們可以讓你在調(diào)用的地方編寫代碼實現(xiàn)后面將要執(zhí)行的操作。
因此Blocks通常作為框架方法的參數(shù)。
它們允許你訪問局部變量。
而不是需要使用一個你想要執(zhí)行操作時集成所有上下文的信息的數(shù)據(jù)結(jié)構(gòu)來
進行回調(diào),你可以直接簡單的訪問局部變量。
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[7]
Blocks Programming Topics
第三章 聲明和創(chuàng)建Blocks3.1聲明一個block的引用
Block變量擁有blocks的引用。你可以使用和聲明函數(shù)指針類似的語法來聲明它
們,除了它們使用^修飾符來替代*修飾符。Block類型可以完全操作其他 C 系統(tǒng)
類型。以下都是合法的block聲明:
Blocks還支持可變參數(shù)(...)。一個沒有使用任何參數(shù)的 block 必須在參數(shù)列表
上面用void標明。
Blocks被設(shè)計為類型安全的,它通過給編譯器完整的元數(shù)據(jù)來合法使用blocks、
傳遞到blocks的參數(shù)和分配的返回值。你可以把一個block引用強制轉(zhuǎn)換為任意類型
的指針,反之亦然。但是你不能通過修飾符 * 來解引用一個block,因此一個block的大小是無法在編譯的時候計算的。
你同樣可以創(chuàng)建blocks的類型。當你在多個地方使用同一個給定的簽名的block時,這通常被認為是最佳的辦法。
3.2創(chuàng)建一個block
你可以使用^修飾符來標識一個block表達式的開始。它通常后面跟著一個被()包含起來的參數(shù)列表。Block的主體一般被包含在 {} 里面。下面的示例定義了一個
簡單的block,并把它賦值給前面聲明的變量(oneFrom)。這里block使用一個標準 C
的結(jié)束符;來結(jié)束。
void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int, char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
typedef float (^MyBlockType)(float, float);
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;
int (^oneFrom)(int);
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[8]
Blocks Programming Topics
oneFrom = ^(int anInt) {
return anInt - 1;
};
如果你沒有顯式的給block表達式聲明一個返回值,它會自動的從block內(nèi)容推
斷出來。如果返回值是推斷的,而且參數(shù)列表也是void,那么你同樣可以省略參數(shù)列
表的void。如果或者當出現(xiàn)多個返回狀態(tài)的時候,它們必須是完全匹配的(如果有必
要可以使用強制轉(zhuǎn)換)。
3.3全局blocks
在文件級別,你可以把block作為全局標示符:
#import
int GlobalInt = 0;
int (^getGlobalInt)(void) = ^{ return GlobalInt; };
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[9]
Blocks Programming Topics
第四章Blocks和變量本文描述blocks和變量之間的交互,包括內(nèi)存管理。
4.1變量類型
在block的主體代碼里面,變量可以被使用五種方法來處理。
你可以引用三種標準類型的變量,就像你在函數(shù)里面引用那樣:
全局變量,包括靜態(tài)局部變量。
全局函數(shù)(在技術(shù)上而言這不是變量)。
封閉范圍內(nèi)的局部變量和參數(shù)。
Blocks同樣支持其他兩種類型的變量:
在函數(shù)級別是__block變量。這些在block里面是可變的(和封閉范圍),并任何引
用block的都被保存一份副本到堆里面。
引入const。
最后,在實現(xiàn)方法里面,blocks也許會引用Objective-C的實例變量。參閱“對象
和Block變量”部分。
在block里面使用變量遵循以下規(guī)則:
全局變量可訪問,包括在相同作用域范圍內(nèi)的靜態(tài)變量。
傳遞給block的參數(shù)可訪問(和函數(shù)的參數(shù)一樣)。
程序里面屬于同一作用域范圍的堆(非靜態(tài)的)變量作為const變量(即只讀)。
它們的值在程序里面的block表達式內(nèi)使用。在嵌套block里面,該值在最近的
封閉范圍內(nèi)被捕獲。
屬于同一作用域范圍內(nèi)并被__block存儲修飾符標識的變量作為引用傳遞因此是
可變的。
屬于同一作用域范圍內(nèi)block的變量,就和函數(shù)的局部變量操作一樣。
每次調(diào)用block都提供了變量的一個拷貝。這些變量可以作為const來使用,或在block封閉范圍內(nèi)作為引用變量。
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[10]
下面的例子演示了使用本地非靜態(tài)變量:
Blocks Programming Topics
int x = 123;
void (^printXAndY)(int) = ^(int y) {
printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 123 456
正如上面提到的,在 block 內(nèi)試圖給 x 賦一個新值會導(dǎo)致錯誤發(fā)生:
int x = 123;
void (^printXAndY)(int) = ^(int y) {
x = x + y; // error
printf("%d %d\n", x, y);
};
為了可以在block內(nèi)修改一個變量,你需要使用__block存儲類型修飾符來標識該
變量。參閱“__block存儲類型”部分。
4.2 __block存儲類型
你可以指定引入一個變量為可更改的,即讀-寫的,通過應(yīng)用__block 存儲類型修
飾符。局部變量的__block的存儲和register、auto、static等存儲類型相似,但它們之
間不兼容。
__block變量保存在變量共享的作用域范圍內(nèi),所有的blocks和block副本都聲明
或創(chuàng)建在和變量的作用域相同范圍內(nèi)。所以,如果任何blocks副本聲明在棧內(nèi)并未超
出棧的結(jié)束時,該存儲會讓棧幀免于被破壞(比如封裝為以后執(zhí)行)。同一作用域范
圍內(nèi)給定的多個block可以同時使用一個共享變量。
作為一種優(yōu)化,block存儲在棧上面,就像blocks本身一樣。如果使用Block_copy拷貝了block的一個副本(或者在Objective-C里面給block發(fā)送了一條copy消息),
變量會被拷貝到堆上面。所以一個__block變量的地址可以隨時間推移而被更改。2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[11]
Blocks Programming Topics
使用__block的變量有兩個限制:它們不能是可變長的數(shù)組,并且它們不能是包
含有 C99 可變長度的數(shù)組變量的數(shù)據(jù)結(jié)構(gòu)。
以下舉例說明了如何使用__block變量:
__block int x = 123; // x lives in block storage
void (^printXAndY)(int) = ^(int y) {
x = x + y;
printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 579 456
// x is now 579
下面的例子顯示了blocks和其他幾個類型變量間的交互:
extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void) {
++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block
creation
localCharacter = 'a'; // sets localCharacter in enclosing scope
};
++localCounter; // unseen by the block
localCharacter = 'b';
aBlock(); // execute the block
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[12]
Blocks Programming Topics
// localCharacter now 'a'
}
4.3對象(Object)和Block變量
Block提供了支持Objective-C和Objective-C++的對象,和其他blocks的變量。
4.3.1Objective-C對象
在引用計數(shù)的環(huán)境里面,默認情況下當你在block里面引用一個Objective-C對象的時
候,該對象會被retain。當你簡單的引用了一個對象的實例變量時,它同樣被retain。
但是被__block存儲類型修飾符標記的對象變量不會被retain.注意:在垃圾回收機制里面,如果你同時使用__weak 和__block 來標識一個變量,那么該 block
將不會保證它是一直是有效的。
如果你在實現(xiàn)方法的時候使用了block,對象的內(nèi)存管理規(guī)則更微妙:如果你通過引用來訪問一個實例變量,self會被retain。
如果你通過值來訪問一個實例變量,那么變量會被retain。
下面舉例說明兩個方式的不同:
dispatch_async(queue, ^{
// instanceVariable is used by reference, self is retained
doSomethingWithObject(instanceVariable);
});
id localVariable = instanceVariable;
dispatch_async(queue, ^{
// localVariable is used by value, localVariable is retained (not self)
doSomethingWithObject(localVariable);
});
4.3.2C++對象
通常你可以在block內(nèi)使用C++的對象。在成員函數(shù)里面,通過隱式的導(dǎo)入this指針引用成員變量和函數(shù),結(jié)果會很微妙。有兩個條件可以讓block被拷貝:2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[13]
Blocks Programming Topics
如果你擁有__block存儲的類,它本來是一個基于棧的C++對象,那么通常會使用copy的構(gòu)造函數(shù)。
如果你在block里面使用任何其他 C++基于棧的對象,它必須包含一個const copy的構(gòu)造函數(shù)。該 C++對象使用該構(gòu)造函數(shù)來拷貝。
4.3.3Blocks
當你拷貝一個block時,任何在該block里面對其他blocks的引用都會在需要的
時候被拷貝,即拷貝整個目錄樹(從頂部開始)。如果你有block變量并在該block里
面引用其他的block,那么那個其他的block會被拷貝一份。
當你拷貝一個基于棧的block時,你會獲得一個新的block。但是如果你拷貝一個
基于堆的block,你只是簡單的遞增了該block的引用數(shù),并把原始的block作為函數(shù)
或方法的返回值。
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[14]
Blocks Programming Topics
第五章 使用Blocks
5.1調(diào)用一個Block
如果你聲明了一個block作為變量,你可以把它作為一個函數(shù)來使用,如下面的
兩個例子所示:
int (^oneFrom)(int) = ^(int anInt) {
return anInt - 1;
};
printf("1 from 10 is %d", oneFrom(10));
// Prints "1 from 10 is 9"
float (^distanceTraveled) (float, float, float) =
^(float startingSpeed, float acceleration, float time) {
float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
return distance;
};
float howFar = distanceTraveled(0.0, 9.8, 1.0);
// howFar = 4.9
然而你通常會把block作為參數(shù)傳遞給一個函數(shù)或方法。在這種情況下,你通過
需要創(chuàng)建一個”內(nèi)聯(lián)(inline)”的block。
5.2使用Block作為函數(shù)的參數(shù)
你可以把一個block作為函數(shù)的參數(shù)就像其他任何參數(shù)那樣。然而在很多情況下,
你不需要聲明blocks;相反你只要簡單在需要它們作為參數(shù)的地方內(nèi)聯(lián)實現(xiàn)它們。下
面的例子使用qsort_b函數(shù)。qsort_b和標準qsort_r函數(shù)類似,但是它最后一個參數(shù)用
block.
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[15]
Blocks Programming Topics
char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" };
qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {
char *left = *(char **)l;
char *right = *(char **)r;
return strncmp(left, right, 1);
});
// Block implementation ends at "}"
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
注意函數(shù)參數(shù)列表包含了一個block。
下一個例子顯示了如何在dispatch_apply函數(shù)里面使用block。dispatch_apply聲明
如下:
該函數(shù)提交一個block給批處理隊列來多次調(diào)用。它需要三個參數(shù);第一個指定
迭代器的數(shù)量;第二個指定一個要提交block的隊列;第三個是block它本身,它自
己需要一個參數(shù)(當前迭代器的下標)。
你可以使用dispatch_apply來簡單的打印出迭代器的下標,如下:
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));
#include
size_t count = 10;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(count, queue, ^(size_t i) {
printf("%u\n", i);
});
5.3使用Block作為方法的參數(shù)
Cocoa提供了一系列使用block的方法。你可以把一個block作為方法的參數(shù)就像
其他參數(shù)那樣。
下面的例子確定數(shù)組前面五個元素中第一個出現(xiàn)在給定的過濾器集中任何一個
的下標。
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[16]
Blocks Programming Topics
NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C", @"A", @"B", @"Z",@"G", @"are",
@"Q", nil];
NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);
test = ^ (id obj, NSUInteger idx, BOOL *stop) {
if (idx < 5) {
if ([filterSet containsObject: obj]) {
return YES;
}
}
return NO;
};
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];
NSLog(@"indexes: %@", indexes);
/*
Output:
indexes: [number of indexes: 2 (in 2 ranges), indexes: (0 3)]
*/
下面的例子確定一個NSSet是否包含一個由局部變量指定的單詞,并且如果條件
成立把另外一個局部變量(found)設(shè)置為 YES(并停止搜索)。注意到found同時被聲
明為__block變量,并且該block是內(nèi)聯(lián)定義的:
__block BOOL found = NO;
NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];
NSString *string = @"gamma";
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[17]
Blocks Programming Topics
if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
*stop = YES;
found = YES;
}
}];
// At this point, found == YES
5.4拷貝Blocks
通常,你不需要copy(或retain)一個block.在你希望block在它被聲明的作用域
被銷毀后繼續(xù)使用的話,你子需要做一份拷貝??截悤?block 移到堆里面。
你可以使用 C 函數(shù)來copy和release一個block:
如果你使用Objective-C,你可以給一個block發(fā)送copy、retain和release(或autorelease)消息。
為了避免內(nèi)存泄露,你必須總是平衡Block_copy()和Block_release()。你必須平衡copy或retain和release(或autorelease)--除非是在垃圾回收的環(huán)境里面。
5.5需要避免的模式
一個block的文本(通常是^{...})是一個代表block的本地棧數(shù)據(jù)結(jié)構(gòu)地址。
因此該本地棧數(shù)據(jù)結(jié)構(gòu)的作用范圍是封閉的復(fù)合狀態(tài),所以你應(yīng)該避免下面例子顯示
的模式:
Block_copy();
Block_release();
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// WRONG: The block literal scope is the "for" loop
}
}
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[18]
$ invoke-block myBlock 10 20
Blocks Programming Topics
void dontDoThisEither() {
void (^block)(void);
int i = random():
if (i > 1000) {
block = ^{ printf("got i at: %d\n", i); };
// WRONG: The block literal scope is the "then" clause
}
// ...
}
5.6調(diào)試
你可以在blocks里面設(shè)置斷點并單步調(diào)試。你可以在一個 GDB 的對話里面使用
invoke-block來調(diào)用一個block。如下面的例子所示:
如果你想傳遞一個 C 字符串,你必須用引號括這它。例如,為了傳遞this string給doSomethingWithString的block,你可以類似下面這樣寫:
$ invoke-block doSomethingWithString "\"this string\""
2011-12-09?|???2011?YouMi?Mobile?Co.?Ltd.?All?Rights?Reserved.?????????????????????[19]
Blocks Programming Topics
結(jié)束語
Block是iOS 4.0之后添加的新特性支持。本人親測感覺使用Block最大的便利就
是簡化的回調(diào)過程。以前使用UIView的動畫,進程要控制動畫結(jié)束后進行相應(yīng)的處
理。iOS 4.0之后,UIView新增了對Block的支持,現(xiàn)在只要使用簡單的一個Block代碼就可以在寫動畫的代碼部分直接添加動畫結(jié)束后的操作。還有就是在使用
Notification時候Block也非常有幫助。反正多用就可以體會到Block的優(yōu)美了。
對了,使用Block要謹記別造成對象互相引用對方導(dǎo)致引用計數(shù)進入一個循環(huán)導(dǎo)
致對象無法被釋放。iOS 5.0之后的ARC也是無法解決該潛在的互相引用的問題的。
所以寫B(tài)lock的時候要注意這點。因為Block往往在后臺自動對一些它引用了的對象
進行retain操作。具體形式這里就不距離了,大家在使用的時候多體會一下。