block代碼塊是OC的一個特性,除了可執行的代碼外,還可能包含變量的自動綁定(棧),或內存托管(堆)。所以一個block維護一個狀態集(數據),可以在任何時候執行。block用來作為回調特別有用。
block可以作為函數參數或者函數的返回值,而本身又可以帶輸入參數或返回值。在多線程,異步任務,集合遍歷,接口回調等地方用得比較多。使用標識符^.。為了性能,block都是分配在棧stack上面的,它的作用域就是當前函數。
我們來說說block和函數的相似性:
(1)可以保存代碼;
(2)有返回值;
(3)有形參;
(4)調用方式一樣;
下面我們使用代碼來演示一下block的用法:
#import輸出結果如下://聲明一個閉包; //沒有返回值,沒有輸入參數; void (^one) (void); //有返回值,沒有輸入參數; int (^two) (void); //沒有返回值,有輸入參數; void (^three) (int); //有返回值,有輸入參數; int (^four) (int ,int); int main(int argc, const char * argv[]) { @autoreleasepool { //定義閉包函數; one = ^(void){ NSLog(@執行了one); }; two = ^(void){ NSLog(@執行了two); return 2; }; three = ^(int a){ NSLog(@執行了three); }; four = ^(int a,int b){ NSLog(@執行了four); return a + b; }; //調用閉包函數; one(); two(); three(1); four(2,3); NSLog(@%d,two()); NSLog(@%d,four(2,3)); } return 0; }
。
同樣,我們可以在聲明的時候直接定義block,示例如下:
#importint main(int argc, const char * argv[]) { @autoreleasepool { //我也可以直接在這裡聲明的時候進行定義; void(^block)(int a) = ^(int a){ NSLog(@%d,a); }; block(3); } return 0; }
輸出結果如下:
。
block非常重要的一個功能就是進行值捕獲。請看一下示例代碼:此時我們只能捕獲num的值,不能去修改它,因為這是一個值類型,進行的是值傳遞。
#importint main(int argc, const char * argv[]) { @autoreleasepool { //Block值捕獲 int num = 10; void(^myBlock)(void) = ^(void){ //我們可以在block內部訪問到外部的變量,但是不能修改; NSLog(@num = %d,num); }; myBlock(); } return 0; }
。
但是如果因為項目實際需要,需要在block內部修改外部變量的值,那麼就可以使用__block關鍵字修飾變量,示例代碼如下:此時的這個變量就變成了引用類型。在block內就可以修改它的值。
但是請注意,只要沒對block進行copy操作,block就一直在在stack中,要想延長block的作用域,就可以進行copy操作,apple提供的接口是Block_Copy()方法,將block復制到heap中。
#importint main(int argc, const char * argv[]) { @autoreleasepool { //Block值捕獲 __block int num = 10; void(^myBlock)(void) = ^(void){ //我們可以在block內部訪問到外部的變量,但是不能修改; NSLog(@num = %d,num); num = 20;//修改外部變量的值; }; myBlock(); NSLog(@numnum = %d,num); } return 0; }
.