本系列文章主要是對《Objective-C 高級編程》這本書做的讀書筆記總結(jié),除了這本書中的內(nèi)容以外钳恕,也加上了自己對開發(fā)技術(shù)的理解和一些個人的經(jīng)驗分享。
一、什么是Blocks
1.1 Blocks概要
Blocks是C語言的擴(kuò)充功能睬关,是帶有局部變量的匿名函數(shù)(匿名其實就是沒有名稱的函數(shù),C語言標(biāo)準(zhǔn)不允許匿名函數(shù))
例如:這里聲明了一個名稱為func的函數(shù)
int func (int count);
為了調(diào)用該函數(shù)毡证,必須使用該函數(shù)的名稱
int result = func (10);
如果像下面這樣电爹,使用函數(shù)指針來代替直接調(diào)用函數(shù),那么不需要使用函數(shù)名也能夠使用該函數(shù)
int result = (*funcPtr) (10);
但其實使用函數(shù)指針也仍然需要知道函數(shù)名稱料睛。例如以下丐箩,在賦值給函數(shù)指針時摇邦,若不使用函數(shù)的名稱,就取法取得該函數(shù)的地址屎勘。
int (*funcPtr)(int) = &func;
int result = (*funcPtr) (10);
而通過Blocks施籍,源代碼中就能夠使用匿名函數(shù)。
匿名函數(shù)大家已經(jīng)知道了概漱,那么現(xiàn)在讓我們來看一下C語言中可能使用的變量有哪些 :
- 局部變量
- 函數(shù)參數(shù)
- 靜態(tài)全局變量
- 靜態(tài)局部變量
- 全局變量
1.2 Blocks語法
下面我們來詳細(xì)講解一下帶有局部變量值的匿名函數(shù)Blocks的語法:
^
返回值類型
參數(shù)列表
表達(dá)式
以下定義表明這是一個表示沒有返回類型丑慎,并且參數(shù)為int型的Block
^ void (int a, int b) {
// do sth
}
如上所示:完整形式的Blocks和C語言的函數(shù)定義區(qū)別為:
- 沒有函數(shù)名 (匿名函數(shù))
- 沒有
^
溫馨小貼士:因為OS X,iOS 應(yīng)用程序的源代碼中大量使用Block瓤摧,所以插入該記號便于查找竿裂。
block可以省略返回類型
省略返回類型的語法為: ^
參數(shù)列表
表達(dá)式
^ void (int a, int b) {表達(dá)式}
等價于
^ (int a, int b) {表達(dá)式}
其次,如果不使用參數(shù)照弥,block也可以省略參數(shù)列表
語法為: ^
表達(dá)式
^ {
// 說點什么吧腻异,少年
}
1.3 Block與C函數(shù)對比
int func (int count)
{
return count + 1;
}
// 函數(shù)func的地址賦值給函數(shù)指針變量funcPtr
// 在block語法下可將block賦值給聲明為block類型的變量
int (*funcPtr) (int) = &func
int (^blockName) (int)
與前面的使用函數(shù)指針的源代碼對比可知,聲明block類型變量僅僅是將聲明函數(shù)指針類型變量 *
變?yōu)?^
int (^block) (int) = ^ (int count) {
return count + 1;
}
block類型變量與c語言變量相同产喉,block也可以作為函數(shù)參數(shù)傳遞或者函數(shù)的返回值
- 作為函數(shù)參數(shù)
void func ( int (^block) (int) ) {
//
}
- 作為函數(shù)的返回值
int (^func()) (int) {
//
return ^ (int count) {
return count + 1;
};
}
由上面源代碼可以看出在使用block變量時捂掰,記錄方式非常復(fù)雜。我們可以像使用函數(shù)指針類型那樣曾沈,使用 typedef
來解決
typedef int (block_t) (int)
我們來對比以下
// 沒有定義前
void func ( int (^block) (int) ) {
}
// 定義后
void func (block_t block) {
}
另外这嚣,Block調(diào)用 和 C語言中使用函數(shù)指針調(diào)用函數(shù)的方法幾乎完全相同。
int result = (*funcPtr)(10);
int result = block(10);
也可以使用指向block類型變量的指針調(diào)用block
typedef int (^block_t) (int)
block_t block = ^ (int count) {
return count + 1;
}
block_t *blockPtr = █
(* blockPtr)(10);
1.4 截獲局部變量值以及__block說明符的使用
1.4.1 截獲局部變量值
截獲局部變量值是指保存執(zhí)行block語法瞬間的值塞俱,并且保存后就不能修改變量值姐帚。
int val = 0;
void (^block) (void) = ^ {
NSLog(@"val = %d", val);
}
val = 1;
block();
執(zhí)行上面源代碼,打印val的值為0障涯。這是因為在block中截獲了局部變量的值罐旗,即保存了該變量的瞬間值。所以即使更改了變量的值也不會影響block的打印唯蝶。
1.4.2__block說明符的使用
執(zhí)行下面源代碼九秀,會產(chǎn)生編譯錯誤。
int val = 0;
void (^block) (void) = ^ {
val = 1;
}
block();
NSLog(@"val = %d", val);
向截獲的變量直接賦值會發(fā)生編譯錯誤粘我,但使用截獲的值卻不會報錯鼓蜒。
id array = [NSMutableArray array];
void (^block) (void) = ^ {
id obj = [[NSObject alloc] init];
[array addObject:obj];
}
block();
若想在block中修改局部變量的值,需要在該自動變量前加 __block
說明符征字。
__block int val = 0;
void (^block) (void) = ^ {
val = 1;
}
block();
NSLog(@"val = %d", val);
源代碼的執(zhí)行結(jié)果為:val = 1