IOS中的Block與C++11中的lambda,ioslambda
ios中的block 可以說是一種函數指標,但更確切的講,其實際上其應該算是object-c對C++11中lambda的支援或者說是一個語言上的變體,其實際內容是一樣的,C++的lambda我已經有簡介過,現在說下ios中的block
Block的實際行為和Function很像,最大的差別是在可以存取同一個Scope的變數值。Block實體形式如下:
^(傳入參數列){行為主體};
Block實體開頭是“^”,接著是由小括弧所包起來的參數列(比如 int a, int b, int c),return a*a;};
這是代表Block會回傳輸入值的平方值(int a 就是參數列, return a*a; 就是行為主體)。記得行為主體裡最後要加“;”,因為是敘述,而整個{}最後也要加“;”,因為Block是物件實體。用法如下:
- int result = ^(int a){return a*a;}(5);
- NSLog(@"%d", result);
很奇怪吧?後面的小括弧裡面的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)
存取變數
1、可以讀取和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"}了。
2、直接存取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);
-
- }
3、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.
iOS中的block可以代替delegate
可以!,如果簡單傳值,用block不錯