【Objective-C】Block介紹

本文部分內(nèi)容摘自。

1.Block是啥?憑什么這么屌?

就本質(zhì)來說,一個Block就是一大堆在接下來某個時間可以被執(zhí)行的代碼。

Block 是一等函數(shù)(first-class function)[1]。一等函數(shù)!這個夢幻般的爵位(如果計算機科學也有爵位的話~),卻揭露了它丫的就是Objective-C的一個常規(guī)對象。因為它也就是個對象,所以它可以作為參數(shù)被傳來傳去,被方法和函數(shù)作為返回值送人,也可以被指定為變量。

Block在一些諸如Python、Ruby、Lisp這樣的語言中被叫做閉包,因為在它被聲明的時候,它肚子里就已然有貨了。一個block會為它范圍內(nèi)的任一變量做個copy,讓小弟吃飽穿暖,別稀里糊涂的生命周期就結束了。

在這貨出現(xiàn)之前,你想完成回調(diào),最典型的就是用delegate或者NSNotificationCenter。這兩個家伙表現(xiàn)挺好的,不過,卻讓你的代碼到處跑,你從一個地方開始任務,卻要在另一個地方處理結果。

Block就機靈得多,在處理任務的時候,它讓你不挪窩,就把事兒給辦了,就像你接下來將要看到的。

2.Block為誰而生?

就是你們!不騙你們,Block是位每一個苦逼程序猿創(chuàng)造的,每個人都該用。Block代表了未來,所以你現(xiàn)在就得學。很多內(nèi)置框架都基于這貨重寫或擴展了。

3.Block怎么用?

下面那張妖里妖氣的圖片,來自蘋果開發(fā)者庫,做了很好的Block句法解釋。

block
block

我從左到右,從上到下翻譯一下:

  • 我們聲明了一個叫“myBlock”的變量,“^”告訴我們這是一個block;
  • 這是一個字面量block的定義,指派給了“myBlock”;
  • "myBlock"是一個返回整型值的block;
  • 它只有一個整型參數(shù);
  • 參數(shù)名字叫“num”;
  • 這是block的貨,也就是block的實現(xiàn)。
    Block的聲明形式如下:
return_type (^block_name)(param_type, param_type, ...)

如果你有C系語言的編程經(jīng)驗的話,這會讓你似曾相識,除了^,^表明“這貨正在聲明一個block”。

如果你腦海中縈繞著:^表示“我是一個block”,恭喜——你已經(jīng)學會使用block最難的部分。(我讀書少,你可不要騙我啊...)

注意,在聲明的時候,給參數(shù)命名不是必要的(只要知道是什么類型就行了),如果你愿意可以加上。

以下是聲明一個block的例子:

int (^add)(int,int)  

接著,是block的定義:

// Block Definition
^return_type(param_type param_name, param_type param_name, ...) { ... return return_type; }

這就是Block的創(chuàng)建形式。要注意,Block的定義和聲明有不同的結構。定義是以^開頭,后面緊跟著參數(shù),這次參數(shù)要有名字啦,并且它們的順序要和Block定義中的一樣。

當定義Block的時候,返回值類型可以不填,因為它可以根據(jù)代碼推斷出來。如果有多個返回的語句,那每個語句返回的必須是同一類型的(或者強轉成相同的類型)。

以下是一個Block定義的例子:


^(int number1, int number2){ return number1+number2 }

如果我們把Block聲明和定義的例子組合在一塊兒,我們得到一個完整的語句:

int (^add)(int,int) = ^(int number1, int number2){ 
                            return number1+number2;
}  

然后我們可以這樣使用:

int resultFromBlock = add(2,2);  

接下來,我們讓用了Block的,和沒用Block的代碼PK一下!

例子:NSArray

我們看看Block怎樣改變了我們操作數(shù)組。
首先,我們看一個常規(guī)的循環(huán):

BOOL stop;
for (int i = 0 ; i < [theArray count] ; i++) {
    NSLog(@"The object at index %d is %@",i,[theArray objectAtIndex:i]);
    if (stop)
        break;
}  

上面方法的stop變量可能讓你覺得沒什么意義。但是,當你看到同一方法但基于Block,它將變得更明晰。Block方式提供一個stop變量,使你能夠隨時停止循環(huán)。我們剛才簡單復制了一些與Block功能相同的代碼。
現(xiàn)在我們再看一個用快速枚舉的代碼:

BOOL stop;
int idx = 0;
for (id obj in theArray) {
    NSLog(@"The object at index %d is %@",idx,obj);
    if (stop)
        break;
    idx++;
}  

最后我們用Block:

[theArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
    NSLog(@"The object at index %d is %@",idx,obj);
}];  

在上面的Block中,你可能好奇stop變量是干嘛的。它是一個簡單變量,可以在Block中被置為YES來停止進一步的處理。

上面的例子有點不知所云,而且很難看出Block有嘛好處(擦~,那你為什么這么寫...)。但是,有兩點是我要指出的:

  • 簡單粗暴。用Block,我們有機會操作數(shù)組里的對象,對象的索引,和一個布爾變量,不用謝任何代碼。而更少的代碼以為著更少的錯誤。
  • 唯快不破。用Block比快速枚舉要有哦輕微的速度上的優(yōu)勢。在此例中,這速度上的優(yōu)勢(可能存在)是如此之小根本沒法發(fā)覺,但在復雜的案例中,這個優(yōu)勢是很重要的(請看官們停止爆粗口吧,作者寫到這里,可能也有點惴惴不安,所以給自己提供了一個證據(jù),來證明自己不是大忽悠...)。

例子:UIView 動畫

讓我們操作一個UIView的簡單動畫。這個動畫就是:把一個UIView從superview上刪掉的時候,讓它的透明度變?yōu)?,并且x、y各增加50。簡單不?

不用Block的方式:

- (void)removeAnimationView:(id)sender {
    [animatingView removeFromSuperview];
}
 
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
 
    [UIView beginAnimations:@"Example" context:nil];
    [UIView setAnimationDuration:5.0];
    [UIView setAnimationDidStopSelector:@selector(removeAnimationView)];
    [animatingView setAlpha:0];
    [animatingView setCenter:CGPointMake(animatingView.center.x+50.0, 
                                         animatingView.center.y+50.0)];
    [UIView commitAnimations];
}

用Block的方式:

  - (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
 
    [UIView animateWithDuration:5.0 
                     animations:^{
                        [animatingView setAlpha:0];
                        [animatingView setCenter:CGPointMake(animatingView.center.x+50.0, 
                                                             animatingView.center.y+50.0)];
                     } 
                     completion:^(BOOL finished) {
                         [animatingView removeFromSuperview];
                     }];
}

觀察這兩個方法,對我來說,Block有3個突出的優(yōu)點:

  • 代碼簡潔。用Block,我們不必聲明每一個單獨的方法來完成回調(diào)。
  • 代碼集中。用Block,我們不用在一個地方開始動畫,在另一個地方執(zhí)行回調(diào),所有與動畫相關的,都在一起,使代碼更加可讀可寫。
  • 蘋果大哥這么說的...這就是一個蘋果用Block重寫已經(jīng)存在的功能的例子。現(xiàn)在蘋果官方建議每位過渡到基于Block的方法(證據(jù))。

4.Block什么時候用?

(誰說外國人不會說官話,請欣賞,咳咳,難道是華裔)
我認為我能給出的最好的建議是,當你覺得合適的時候,你就該用了(hehe~)。很有可能你還想用你以前的方法,因為代碼維護啊、適配啊,你用以前的方法更得心應手。但是每次你都要想想,是否Block能簡化你的生活,是否可以用基于Block的方法來代替。然后選擇最優(yōu)的。

當然,你會發(fā)現(xiàn)你在將來需要用越來越多的Block,因為很多框架,無論是第三方的,或者蘋果自己的,已經(jīng)用Block寫了或者重寫了很多方法。所以現(xiàn)在開始就用Block吧,這樣在面對未來的時候,你才能算有備而來(一句話,形勢比人強,程序猿,看著辦吧)。

5.創(chuàng)建自己的Block

Block的好,已經(jīng)說半天了,你肯定已經(jīng)迫不及待的想寫一些Block了,下面給一些代碼片段:

// 這是一個用Block做參數(shù)的方法
- (void)doMathWithBlock:(int (^)(int, int))mathBlock {
    self.label.text = [NSString stringWithFormat:@"%d", mathBlock(3, 5)];
}
 
// 調(diào)用上面的方法
- (IBAction)buttonTapped:(id)sender {
    [self doMathWithBlock:^(int a, int b) {
        return a + b;
    }];
}

因為Block就是一個Objective-C的對象,所以你可以把它作為一個屬性,以便你再調(diào)用。這在回調(diào)中相當有用。以下是一個例子:

// 聲明一個屬性
@property (strong) int (^mathBlock)(int, int); // 不用ARC的話,“strong”改為“copy”
 
// 將方法參數(shù)中的block儲存到屬性,方便以后調(diào)用
- (void)doMathWithBlock:(int (^)(int, int))mathBlock {
    self.mathBlock = mathBlock;
}
 
// 調(diào)用方法
- (IBAction)buttonTapped:(id)sender {
    [self doMathWithBlock:^(int a, int b) {
        return a + b;
    }];
}
 
// 接下來就可以用屬性了...
- (IBAction)button2Tapped:(id)sender {
    self.label.text = [NSString stringWithFormat:@"%d", self.mathBlock(3, 5)];
}

最后,你可以用typedef簡化一下句法。我們把上面的例子改造一下:

// 用typedef創(chuàng)建一種Block類型
typedef int (^MathBlock)(int, int);
 
// 用此類型定義一個屬性
@property (strong) MathBlock mathBlock;
 
// 將方法參數(shù)中的block儲存到屬性,方便以后調(diào)用
- (void)doMathWithBlock:(MathBlock) mathBlock {
    self.mathBlock = mathBlock;
}
 
// 調(diào)用方法
- (IBAction)buttonTapped:(id)sender {
    [self doMathWithBlock:^(int a, int b) {
        return a + b;
    }];
}
 
// 接下來就可以用屬性了...
- (IBAction)button2Tapped:(id)sender {
    self.label.text = [NSString stringWithFormat:@"%d", self.mathBlock(3, 5)];
}

6.BlockDelegateDemo

最后,如果你想比較一下BlockDelegate實現(xiàn)回調(diào)的異同,這里有我的一個簡單Demo。


  1. 在計算機科學中,如果一個編程語言把函數(shù)當作一等公民,那么就說它有一等函數(shù)。具體來說,該語言支持把函數(shù)當作一個參數(shù)來傳遞、可以作為其他函數(shù)的返回值來返回、可以把它定義為變量,同時,也可以把它作為一種數(shù)據(jù)結構來存儲。(翻譯自維基百科·First-class funcion) ?

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 禪與 Objective-C 編程藝術 (Zen and the Art of the Objective-C C...
    GrayLand閱讀 1,770評論 1 10
  • 前言 Blocks是C語言的擴充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了這...
    小人不才閱讀 3,861評論 0 23
  • 在前兩篇中,我們介紹了一些關于C語言的重要概念,指針跟struct,這些基礎知識是我們深入學習block的前提,在...
    ccSundayChina閱讀 598評論 2 3
  • 我向天空大聲地質(zhì)問青春是什么顏色的 它用一條彩虹告訴我 青春是五顏六色的 我向大海大聲地質(zhì)問青春是什么聲音的 它用...
    楊安勁閱讀 243評論 0 2
  • 兩個人在一起,相處和陪伴很重要,但如果貼太緊,卻會讓對方喘不過氣。要是分開的太遠,又很容易疏離。所以戀愛的最好方式...
    篤學青衿閱讀 118評論 0 1

友情鏈接更多精彩內(nèi)容