iOS中的Block用法

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


  1. ^(int a){return a*a;};  table


這是表明Block會回傳輸入值的平方值(int a 就是參數列 return a*a; 就是行爲主體)。記得行爲主體裏最後要加「;」,由於是敘述,而整個{}最後也要加「;」,由於Block是物件實體。用法以下:ast


  1. int result = ^(int a){return a*a;}(5);  function

  2. NSLog(@"%d", result);  test


很奇怪吧?後面的小括號裏面的5會被當成a的輸入值,而後經由Block輸出 5*5 = 25指定給result這個變量。

有沒有簡單一點的方法嗯?否則每次都寫這麼長?有。接下來介紹一個叫作Block Pointer的東西來簡化咱們的寫法。

Block Pointer是這樣定義的:

回傳值(^名字)(參數列);

好比下面的例子:


  1. //聲明一個square的Block Pointer,其所指向的Block有一個int輸入和int輸出  

  2. int (^square)(int);  

  3. //將Block實體指定給square  

  4. square = ^(int a){ return a*a ; };  

  5. //調用方法,感受是是否是很像function的用法?  

  6. int result = square(5);  

  7. NSLog(@"%d", result);  

是否是變的簡單了?

也能夠吧Block Pointer當成參數傳遞給一個function,好比:


  1. void myFunction(int (^mySquare)(int));     //function的定義,將Block做爲參數  

  2. int (^mySquare)(int) = ^(int a){return a*a;};   //定義一個mySquare的Block pointer變量  

  3. myFunction(mySquare);    //把mySquare做爲myFunction的參數  


上面的三行代碼其實等價於下面這行代碼:


  1. myFunction( ^int(int a){return a*a;} );  


當其做爲Object-C method的傳入值的話,須要把類型寫在變量前面,而後加上小括號。好比下面這種寫法:


  1. -(void)objcMethod:(int(^)(int))square;  //square參數的類型是int(^)(int)  


存取變量

一、能夠讀取和Block pointer同一個Scope的變量值:


  1. {  

  2.     int outA = 8;  

  3.     int (^myPtr)(int) = ^(int a){ return outA + a;};  

  4.     //block裏面能夠讀取同一類型的outA的值  

  5.     int result = myPtr(3);  // result is 11  

  6.     NSLog(@"result=%d", result);  

  7. }  


下面來看一段頗有意思的代碼:


  1. {  

  2.     int outA = 8;  

  3.     int (^myPtr)(int) = ^(int a){ return outA + a;}; //block裏面能夠讀取同一類型的outA的值  

  4.       

  5.     outA = 5;  //在調用myPtr以前改變outA的值  

  6.     int result = myPtr(3);  // result的值仍然是11,並非8  

  7.     NSLog(@"result=%d", result);  

  8. }  


爲何result 的值仍然是11?而不是8呢?事實上,myPtr在其主體中用到的outA這個變量值的時候作了一個copy的動做,把outA的值copy下來。因此,以後outA即便換成了新的值,對於myPtr裏面copy的值是沒有影響的。

須要注意的是,這裏copy的值是變量的值,若是它是一個記憶體的位置(地址),換句話說,就是這個變量是個指針的話,

它的值是能夠在block裏被改變的。以下例子:


  1. {  

  2.     NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];  

  3.     int result = ^(int a){[mutableArray removeLastObject]; return a*a;}(5);  

  4.     NSLog(@"test array :%@", mutableArray);  

  5. }  


本來mutableArray的值是{@"one",@"two",@"three"},在block裏面被更改mutableArray後,就變成{@"one"@"two"}了。

二、直接存取static類型的變量


  1. {  

  2.     static int outA = 8;  

  3.     int (^myPtr)(int) = ^(int a){return outA + a;};  

  4.     outA = 5;  

  5.     int result = myPtr(3);  //result的值是8,由於outA是static類型的變量  

  6.     NSLog(@"result=%d", result);  

  7.       

  8. }  

甚至能夠直接在block裏面修改outA的值,例以下面的寫法:


  1. {  

  2.     static int outA = 8;  

  3.     int (^myPtr)(int) = ^(int a){ outA = 5; return outA + a;};  

  4.     int result = myPtr(3);  //result的值是8,由於outA是static類型的變量  

  5.     NSLog(@"result=%d", result);  

  6.       

  7. }  


三、Block Variable類型的變量

在某個變量前面若是加上修飾字「__block」的話(注意,block前面有兩個下劃線),這個變量就稱做block variable。

那麼在block裏面就能夠任意修改此變量的值,以下代碼:


  1. {  

  2.     __block int num = 5;  

  3.       

  4.     int (^myPtr)(int) = ^(int a){return num++;};  

  5.     int (^myPtr2)(int) = ^(int a){return num++;};  

  6.     int result = myPtr(0);   //result的值爲5,num的值爲6  

  7.     result = myPtr2(0);      //result的值爲6,num的值爲7  

  8.     NSLog(@"result=%d", result);    

  9.   

  10. }  

由於myPtr和myPtr2都有用到num這個block variable,最終num的值爲7.

相關文章
相關標籤/搜索