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é)束
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ò)!! } }];
上面的代碼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í),變量又回到棧中。
還是上面的代碼,我們作下修改,如下:
__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提前終止了!");
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ù)組
property (nonatomic, strong) NSMutableArray *blockArray; ... - (void) someMethod { [self.blockArray addObject:^{ ... }]; } // 獲取數(shù)組中的block并調(diào)用 void (^doit)(void) = self.blockArray[0]; doit();