blocks blocks是c語言的擴充,他是:帶有自動變量(局部變量)的匿名函數。 這個概念叫做:閉包。如python中的lambda,在c++11中也引入了lambda; 維基百科中關於閉包:閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。閉包在運行時可以有多個實例,不同的引用環境和相同的函數組合可以產生不同的實例。 blocks的語法: ^ 返回值類型 參數列表 表達式 ^ 參數列表 表達式 ^ 表達式
^void (int i){ printf("%d", i);} ^(int i){printf("%d", i);} ^{printf("123");}
這裡要注意,當你省略返回值類型的時候,你的表達式裡return返回什麼類型,那麼你的返回值類型就是什麼。 當你不適用參數的時候,(void) 參數列表可以省略。
在使用block的時候,我們可以聲明block變量,他同c中的函數指針:
int f(int a) {
return a;
}
int (*fa)(int) = &f;
在blocks中,block指源代碼中的block語法,也指由block語法生成的值。
int (^blk)(int);
int (^blk)(int) = ^(int a){ printf("%d, a); }
int (^blk1)(int) = blk;
int (^blk2)(int);
blk2 = blk1;
void f(int (^blk)(int)); //向函數傳遞block int (^f()(int)); //將block作為返回值返回。
可以使用typedef:
typedef int (^blk_t)(int);
void f(int (^blk)(int)) 對應: void f(blk_t blk)
int (^f()(int)) 對應: blk_t f();
比較函數指針:
int (*ff(int))(int *, int);
這個有點難理解了,我們要從裡往外看:
ff(int) 這裡將ff聲明為一個函數,它有一個int的形參。
這個函數的返回值就是int (*)(int *, int);
這是一個指向函數的指針。我們來變一下形式:
[cpp] view plaincopy
- typedef int (*func)(int*, int);
- func ff(int)
這裡可以看到,他們只有一個* 和一個 ^ 的區別。 他可以作為:自動變量,函數參數,靜態變量,靜態全局變量,全局變量使用。 block類型變量可以和c語言中其他類型變量一樣使用。 如:
typedef int (^blk_t)(int);
blk_t blk = ^(int count){return count;};
blk_t *blkptr = &blk;
(*blkptr)(10);
自動變量 來說一下自動變量: block表達式截獲所使用的自動變量的值:保存該自動變量的瞬間值。 代碼解釋:
int val = 0;
void (^blk)(void) = ^{printf("%d", val);};
val = 3;
blk();
此時,輸出的是0而不是3.
__block
自動變量值截獲只能保存執行block語法瞬間的值,保存後不能改寫了。 當你在block改寫截獲的自動變量時,會產生編譯錯誤。 如果想要在block語法的表達式中將值付給block語法外聲明的自動變量,那麼需要在這個自動變量上附加__block說明符: __block int a = 0; void (^blk)(void) = ^{a = 1;}; blk();
獲取的自動變量
id array = [[NSMutableArray alloc]init];
void (^blk)(void) = ^{id obj = [[NSObject alloc]init];
[array addObject:obj];};
id array = [[NSMutableArray alloc]init];
void (^blk)(void) = ^{array = [[NSMutableArray alloc]init];};
上面兩段代碼第二段會出現錯誤,應該加上__block說明符。 因為向截獲的變量array賦值會產生編譯錯誤。但是使用截獲的值是不會產生任何問題的。
const char text[] = "hello"; void (^blk)(void) = ^{printf("%c", text[2]);};
const char *text = "hello"; void (^blk)(void) = ^{printf("%c", text[2]);}; 上面兩段代碼會出現不同的結果,第一段會報錯,因為截獲自動變量的方法沒有實現對c數組的截獲。
-----2014/3/18 Beijing