一、Blocks概要
1.1 什么是Blocks
Blocks是C語言的擴(kuò)充功能:帶有自動(dòng)變量(局部變量)的匿名函數(shù)
C語言代碼
int buttonId ;
void buttonCallback(int event)
{
printf("buttonId:%d event=%d\n",buttonId, event);
}
void setButtonCallbacks()
{
for (int i = 0;i < BUTTON_MAX;i++) {
buttonId = i;
setButtonCallback(BUTTON_IDOFFSET + i, &buttonCallback);
}
}
說明:本段代碼為了設(shè)置每個(gè)按鈕的buttonId,可見在C語言中攀痊,需要有名函數(shù)蜈七,需要全局變量藻懒。
Block實(shí)現(xiàn)
void setButtonCallbacks()
{
for (int i = 0;i < BUTTON_MAX;i++) {
buttonId = i;
setButtonCallbackUsingBlock(BUTTON_IDOFFSET + i, ^(int event){
printf("buttonId:%d event=%d\n", i, event);
});
}
}
說明:本段代碼將“帶有自動(dòng)變量i值的匿名函數(shù)”設(shè)置為按鈕的回調(diào)转培。使用Blocks可以不用聲明C++和Object-C類唾糯,也沒有使用靜態(tài)變量诚啃、靜態(tài)全局變量或全局變量的問題淮摔,也沒有使用函數(shù)名。
OC中Block在其他程序語言中的名稱如下圖
程序語言 | Block名稱 |
---|---|
C + Blocks | Block |
Smalltalk | Block |
Ruby | Block |
LISP | Lambda |
Python | Lambda |
C++11 | Lambda |
Javascript | Anonymous function |
二始赎、 Blocks模式
2.1 Block 語法
上節(jié)的代碼Block語法如下:
^(int event){
printf("buttonId:%d event=%d\n", i, event);
}
實(shí)際上和橙,該Block語法使用了省略模式,完整如下:
^ void (int event){
printf("buttonId:%d event=%d\n", i, event);
}
Block語法如下:
^
返回值類型
參數(shù)列表
表達(dá)式
- 沒有函數(shù)名
- 帶有
^
雖然上面出現(xiàn)過省略模式造垛,但Block語法可省略好幾個(gè)項(xiàng)目胃碾。
- 省略返回類型
^
參數(shù)列表
表達(dá)式
舉例:
^ (int count) {return count + 1;}
如果表達(dá)式中有return,返回類型就使用該返回值的類型筋搏,這里的返回類型就是Int仆百,如果沒有ruturn,返回類型就是void
- 省略返回類型和參數(shù)列表
^
表達(dá)式
舉例:
^ {printf("Blocks\n");}
2.2 Block類型變量
- 定義一個(gè)block類型的變量
int (^blk)(int) = ^(int count){return count + 1;};
blk(10);//11
- 函數(shù)中傳遞block參數(shù)
- (void)func:(int (^)(int param))block {
NSLog(@"%d",block(10));//11
}
[self func:^int(int param) {
return param + 1;
}];
- block參數(shù)作為返回值
- (int (^)(int param))functionBlock {
return ^(int param){return param + 1;};
}
NSLog(@"%d",self.functionBlock(10));//11
- 劃重點(diǎn)
我們可以使用typedef int(^blk)(int);
來聲明一個(gè)blk的類型變量
聲明后的block2奔脐、3變成如下形式,是不是感覺這種方式更加的程序員俄周,blk就好像NSString *
一樣對變量進(jìn)行類型聲明
- (void)func:(blk)block {
NSLog(@"%d",block(10));
}
- (blk)functionBlock {
return ^(int param){
return param + 1;
};
}
2.3截獲自動(dòng)變量值
int val = 10;
void (^blk)(void) = ^{
NSLog(@"%d",val);
};
val = 20;
blk();
NSLog(@"%d",val);//10
block中,block表達(dá)式解惑所使用的自動(dòng)變量val的值髓迎,即保存該自動(dòng)變量的瞬間值峦朗,這些值在執(zhí)行塊時(shí)使用,這就是自動(dòng)變量值的截獲排龄。
2.4__block說明符
如果在2.3中我們在block塊中修改val的值會如何呢波势?編譯器會產(chǎn)生編譯錯(cuò)誤。但很多時(shí)候我們需要修改自動(dòng)截獲的變量的值并讓其發(fā)生改變橄维,我們該如何解決呢尺铣?很簡單,在需要修改的變量前面加上__block
說明符即可争舞。
__block int val = 10;
void (^blk)(void) = ^{
NSLog(@"%d",val);//20
val = 30;
NSLog(@"%d",val);//30
};
val = 20;
blk();
NSLog(@"%d",val);//30
使用__block就可以在block中進(jìn)行賦值凛忿,或者在block外面修改自動(dòng)變量的值,被修飾的變量也稱為__block變量竞川。
如果沒有被__block修飾店溢,只要不對變量進(jìn)行賦值操作叁熔,是不會報(bào)編譯錯(cuò)誤的,而且調(diào)用block塊中的對象調(diào)用自己的方法也是沒有問題的,如下面所示:
id array = [NSMutableArray array];
void (^blk)(void) = ^ {
id obj = [[NSObject alloc] init];
[array addObject:obj];
};
blk();
- 注意
在block中使用指針時(shí)需要特別小心床牧,因?yàn)閎lock截獲自動(dòng)變量的方法中并沒有實(shí)現(xiàn)對C語言數(shù)組的截獲荣回。
下面這段代碼編譯會報(bào)錯(cuò)
const char text[] = "hello";
void (^blk)(void) = ^{
printf("%c\n",text[2]);
};
blk();
使用指針可以解決該問題:
const char *text = "hello";
void (^blk)(void) = ^{
printf("%c\n",text[2]);
};
blk();