1. Block類型定義:返回值類型(^ 變量名)(參數列表)(注意Block也是一種類型);
2. Block的typedef定義:返回值類型(^類型名稱)(參數列表);
3. Block的實現:^(參數列表){操做主體};
4. Block中能夠讀取塊外面定義的變量可是不能修改,若是要修改那麼這個變量必須聲明_block修飾;spa
Block簡介:指針
Block的實際行爲和Function很像,最大的差異是在能夠存取同一個Scope的變量值。Block實體形式以下:three
^(傳入參數列){行爲主體};rem
Block實體開頭是「^」,接着是由小括號所包起來的參數列(好比 int a, int b, int c),行爲主體由大括號包起來,專有名字叫作block literal。行爲主體能夠用return回傳值,類型會被compiler自動辨別。若是沒有參數列要寫成: ^(void)。it
例以下面的一個例子:io
^(int a){return a*a;}; table
這是表明Block會回傳輸入值的平方值(int a 就是參數列, return a*a; 就是行爲主體)。記得行爲主體裏最後要加「;」,由於是敘述,而整個{}最後也要加「;」,由於Block是物件實體。用法以下:ast
int result = ^(int a){return a*a;}(5); function
NSLog(@"%d", result); test
很奇怪吧?後面的小括號裏面的5會被當成a的輸入值,而後經由Block輸出 5*5 = 25指定給result這個變量。
有沒有簡單一點的方法嗯?否則每次都寫這麼長?有。接下來介紹一個叫作Block Pointer的東西來簡化咱們的寫法。
Block Pointer是這樣定義的:
回傳值(^名字)(參數列);
好比下面的例子:
//聲明一個square的Block Pointer,其所指向的Block有一個int輸入和int輸出
int (^square)(int);
//將Block實體指定給square
square = ^(int a){ return a*a ; };
//調用方法,感受是是否是很像function的用法?
int result = square(5);
NSLog(@"%d", result);
是否是變的簡單了?
也能夠吧Block Pointer當成參數傳遞給一個function,好比:
void myFunction(int (^mySquare)(int)); //function的定義,將Block做爲參數
int (^mySquare)(int) = ^(int a){return a*a;}; //定義一個mySquare的Block pointer變量
myFunction(mySquare); //把mySquare做爲myFunction的參數
上面的三行代碼其實等價於下面這行代碼:
myFunction( ^int(int a){return a*a;} );
當其做爲Object-C method的傳入值的話,須要把類型寫在變量前面,而後加上小括號。好比下面這種寫法:
-(void)objcMethod:(int(^)(int))square; //square參數的類型是int(^)(int)
存取變量
一、能夠讀取和Block pointer同一個Scope的變量值:
{
int outA = 8;
int (^myPtr)(int) = ^(int a){ return outA + a;};
//block裏面能夠讀取同一類型的outA的值
int result = myPtr(3); // result is 11
NSLog(@"result=%d", result);
}
下面來看一段頗有意思的代碼:
{
int outA = 8;
int (^myPtr)(int) = ^(int a){ return outA + a;}; //block裏面能夠讀取同一類型的outA的值
outA = 5; //在調用myPtr以前改變outA的值
int result = myPtr(3); // result的值仍然是11,並非8
NSLog(@"result=%d", result);
}
爲何result 的值仍然是11?而不是8呢?事實上,myPtr在其主體中用到的outA這個變量值的時候作了一個copy的動做,把outA的值copy下來。因此,以後outA即便換成了新的值,對於myPtr裏面copy的值是沒有影響的。
須要注意的是,這裏copy的值是變量的值,若是它是一個記憶體的位置(地址),換句話說,就是這個變量是個指針的話,
它的值是能夠在block裏被改變的。以下例子:
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
int result = ^(int a){[mutableArray removeLastObject]; return a*a;}(5);
NSLog(@"test array :%@", mutableArray);
}
本來mutableArray的值是{@"one",@"two",@"three"},在block裏面被更改mutableArray後,就變成{@"one", @"two"}了。
二、直接存取static類型的變量
{
static int outA = 8;
int (^myPtr)(int) = ^(int a){return outA + a;};
outA = 5;
int result = myPtr(3); //result的值是8,由於outA是static類型的變量
NSLog(@"result=%d", result);
}
甚至能夠直接在block裏面修改outA的值,例以下面的寫法:
{
static int outA = 8;
int (^myPtr)(int) = ^(int a){ outA = 5; return outA + a;};
int result = myPtr(3); //result的值是8,由於outA是static類型的變量
NSLog(@"result=%d", result);
}
三、Block Variable類型的變量
在某個變量前面若是加上修飾字「__block」的話(注意,block前面有兩個下劃線),這個變量就稱做block variable。
那麼在block裏面就能夠任意修改此變量的值,以下代碼:
{
__block int num = 5;
int (^myPtr)(int) = ^(int a){return num++;};
int (^myPtr2)(int) = ^(int a){return num++;};
int result = myPtr(0); //result的值爲5,num的值爲6
result = myPtr2(0); //result的值爲6,num的值爲7
NSLog(@"result=%d", result);
}
由於myPtr和myPtr2都有用到num這個block variable,最終num的值爲7.