如何在iOS中使用Block

轉載自 http://www.devdiv.com/home.php?mod=space&uid=34689&do=blog&id=6012


Block可以幫助我們組織獨立的代碼段,並提高複用性和可讀性。iOS4在UIKit中引入了該特徵。超過100個的Apple API都使用了Block,所以這是一個我們必須開始熟悉的知識。


Block是什麼樣的? 
你可以使用^操作符來聲明一個Block變量,它表示一個Block的開始。

  1. int num1 = 7;  
  2. int(^aBlock)(int) = ^)int num2) {  
  3.    return num1+nunm2;  
  4. };  

在如上代碼中我們將Block聲明爲一個變量,所以可以將它當做一個函數中使用:

  1. NSLog(@"%d", aBlock(49)); //adds 49 to 7 which gives us 56.  

我們剛看過了將block當做變量的情況,但通常情況下我們會以內聯的方式使用Block,比如在一個變量中。API要麼會使用Block在一個對象集合上執行某種操作,要麼將其作爲一個操作完成後的回調。

  1. NSComperator compareStringsBlock = ^(id stringA, id stringB) {  
  2. NSRange rangeS  = NSMakeRange (0, [stringA length]);  
  3.   return (stringA compare:stringB options:comparisonOptions range:rangeS locale:currentLocale];  
  4. };  
  5.  
  6. NSArray *compareSortArray  = [arrayOfStringDays sortArrayUsingComparator: compareStringsBlock]);  

Block具有將臨時函數體創建爲表達式的優勢。Apple文檔中指出: 
Block是符合如下要求的匿名內聯的代碼集:

  • 和函數一樣具有一個指定類型的參數列表
  •  有一個可以推導或聲明的返回值類型
  • 可以從它被定義的詞義範圍中捕捉狀態
  • 可以在需要的時候改變詞義範圍的狀態
  • 可以和相同的詞義範圍中定義的其他的Block共享更改的可能。
  • 可以在詞義範圍(堆棧幀)被銷燬後繼續共享和修改該詞義範圍(堆棧幀)的狀態。

Block是一個自包含的小代碼段,封裝了用於遍歷(線性遍歷)或者回調,可以併發執行的任務單元。


聲明和使用Block 
Apple文檔中介紹瞭如何將一個Block聲明爲變量,並將其作爲一個函數使用:
 

  1. int (^oneFrom)(int) = ^(int anInt) {  
  2.     return anInt - 1;  
  3. };  
  4. // 我們創建了一個內聯塊^(int anInt)... ,其函數體和結果被傳到了另外一個名爲OneFrom的Block。  
  5.  
  6. printf("1 from 10 is %d", oneFrom(10));  
  7. // 打印出: "1 from 10 is 9"  
  8. // 這個block函數(distanceTraveled)傳入3個float型參數,返回float值。   
  9.  
  10. float (^distanceTraveled) (float, float, float) =  
  11.  
  12.                           ^(float startingSpeed, float acceleration, float time) {  
  13.     float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);  
  14.     return distance;  
  15. }; 


  你也可以傳入一個Block作爲一個參數,而不要以如上的方式聲明它們,這樣就可以在需要將block作爲參數的時候以內聯代碼的方式簡單地實現。

  1. NSArray *anArray = [NSArray arrayWithObjects: @"cat", @"dog",nil];  
  2. sortFunction(anArray, ^(string *a string *b){  
  3. if ( a == @"cat"return TRUE; }); 


這樣我們就看到一個內聯的block代碼段佔據了最後一個參數(必須是參數列表的最後一個參數)的位置。Cocoa提供了很多使用Block的方法,這樣你就可以傳入Block作爲方法的參數:

  1. NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C",  nil];  
  2. NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];  
  3.  
  4. BOOL (^test)(id obj, NSUInteger idx, BOOL *stop); //Block declaration returns BOOL, params inc. id and BOOL  
  5. //body of block gets the block literal ^(id obj, NSUInteger idx, Bool *stop)... and the body logic   
  6. test = ^ (id obj, NSUInteger idx, BOOL *stop) {  
  7.     if (idx < 5) {  
  8.         if ([filterSet containsObject: obj]) {  
  9.             return YES;  
  10.         }  
  11.     }  
  12.     return NO;  
  13.  
  14. }; 

Apple提供的另外一個例子是:

  1. __block BOOL found = NO;  
  2. NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];  
  3. NSString *string = @"gamma";  
  4. //we provide below a way of how to enumerate, using our own compare logic  
  5. [aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {  
  6.     if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {  
  7.         *stop = YES;  
  8.         found = YES;  
  9.     }  
  10. }]; 

掌握它需要一點時間,但一旦領會了還是很簡答的,是不?我建議大家看下Apple的文檔,並看看其中引用到的一些API以確認下它們是如何使用的。多練習,熟能生巧


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章