1. 首先,我們快速過一下,什么是Block?

Block是一段代碼,它在OC中以^開頭,可以有返回值,和參數(shù)列表,但就是沒有名字。

所以,你可以把它認(rèn)為是匿名函數(shù)。

事實(shí)上,它和Swift中的閉包(Closure)是一樣的。

或者,學(xué)過.NET的童鞋知道委托吧,它和委托也差不多概念。

都是可以在一個(gè)方法中傳入它,作為參數(shù)的方法。

 

無參無返回值的Block:

[MyObject myMethodParam1: xx param2: ^{

...

}];

有參有返回值的Block:

[MyObject myMethodParam1: xx param2: ^BOOL(id param1, id param2) {

...

}];

 

好了,說了那么多,我們來看個(gè)例子:

myDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
    NSLog(@"Key - %@: Value - %@", key, value); if ([@"END" isEqualToString:key]) { *stop = YES;
    }
}];

上面這段代碼枚舉一個(gè)字典的鍵值對(duì),知道遇到END鍵值退出循環(huán),否則枚舉所有的鍵值對(duì)。

 

2. 在Block中我們可不可以使用Block范圍以外聲明的變量呢?

答案是可以的,但是它是只讀的,你如果要修改這個(gè)變量,會(huì)編譯錯(cuò)誤。

我們還是來看上面那段代碼的例子,在循環(huán)中,我們?cè)黾恿艘粋€(gè)外部變量,想要讓Block提早結(jié)束

復(fù)制代碼
BOOL stopEarly = NO; double stopValue = 100.2;
[myDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
    NSLog(@"Key - %@: Value - %@", key, value); if ([@"END" isEqualToString:key] || [value doubleValue] == stopValue) { *stop = YES;
        stopEarly = YES; // 這段代碼編譯會(huì)出錯(cuò)!!  }
}];
復(fù)制代碼

上面的代碼stopValue變量的Block內(nèi)讀取沒有任何問題,但是當(dāng)我們企圖在Block內(nèi)修改stopEarly變量的值時(shí),編譯出錯(cuò)了!

 

那么如果,我們執(zhí)意要修改Block外面的變量,是不是可以呢?

答案是可以的。

我們要使用__block關(guān)鍵字,原理上是通過使用該關(guān)鍵字,我們可以把block外的變量從棧中移到堆中,這樣就可以在Block內(nèi)部使用了。

當(dāng)Block結(jié)束時(shí),變量又回到棧中。

還是上面的代碼,我們作下修改,如下:

復(fù)制代碼
__block BOOL stopEarly = NO; double stopValue = 100.2;
[myDict enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
    NSLog(@"Key - %@: Value - %@", key, value); if ([@"END" isEqualToString:key] || [value doubleValue] == stopValue) { *stop = YES;
        stopEarly = YES; 
    }
}]; if (stopEarly)
    NSLog(@"Block提前終止了!");
復(fù)制代碼

 

3. 當(dāng)我們向Block內(nèi)的對(duì)象發(fā)送消息時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)指向該對(duì)象的強(qiáng)指針

該強(qiáng)指針會(huì)一直保留到Block超出自己的范圍,不存在。

 

4. Block數(shù)組

復(fù)制代碼
property (nonatomic, strong) NSMutableArray *blockArray;

... - (void) someMethod {
    [self.blockArray addObject:^{
        ...
    }];
} // 獲取數(shù)組中的block并調(diào)用 void (^doit)(void) = self.blockArray[0];
doit();
復(fù)制代碼