Block對象的示例:
^{
NSLog(@"This is an instruction within a block.");
}
和C函數類似,但是沒有函數名,相應的位置只有一個^符號。^表示這段代碼是一個Block對象。
和函數一樣,Block對象也可以有實參和返回值。
^(double dividend, double divisor){
double quotient = dividend / divisor;
return quotient;
}
代碼中兩個double類型的實參,還返回一個double類型的值。
Block對象可以被當作一個實參來傳遞給可以接收block的方法。
創建一個新項目,名稱爲VowelMovement。該項目將使用Block對象枚舉數組中的字符串並移除所有的元音字母,並將去除元音字母的字符串保存到一個新的數組中。
main.m,創建3個數組對象,一個用於保存最初的字符串,一個用於保存去除了元音字母的字符串,最後一個用於保存需要從字符串中移除的字符。
int main(int argc, const char * argv[]) {
@autoreleasepool {
//創建兩個數組對象,分別用於保存最初的字符串對象和去除元音字母后的版本
NSArray *originalStrings = @[@"Sauerkraut",@"Raygun",@"Big Nerd Ranch",@"Mississippi"];
NSLog(@"origianl strings:%@",originalStrings);
NSMutableArray *devowelizedStrings = [NSMutableArray array];
//創建數組對象,保存需要從字符串中移除的字符
NSArray *vowels = @[@"a",@"e",@"i",@"o",@"u"];
return 0;
}
1、使用Block對象
編寫一個Block對象,用於複製一個給定的字符串,並移除給定字符串的所有元音字母,然後將去除元音字母的字符串保存到devowelizedStrings數組中。
int main(int argc, const char * argv[]) {
@autoreleasepool {
//
NSArray *originalStrings = @[@"Sauerkraut",@"Raygun",@"Big Nerd Ranch",@"Mississippi"];
NSLog(@"origianl strings:%@",originalStrings);
NSMutableArray *devowelizedStrings = [NSMutableArray array];
NSArray *vowels = @[@"a",@"e",@"i",@"o",@"u"];
//聲明Block變量,void是返回類型,第一個()中^表明是一個Block對象,devowelizer是Block對象名稱,後邊的是實參類型
void (^devowelizer)(id, NSUInteger, BOOL *);
//將Block對象賦值給變量
devowelizer = ^(id string, NSUInteger i, BOOL *stop){
//
NSMutableString *newString = [NSMutableString stringWithString:string];
//枚舉數組中的字符串,將所有出現的元音字母替換成空字符串
for(NSString *s in vowels){
NSRange fullRange = NSMakeRange(0, [newString length]);
[newString replaceOccurrencesOfString:s withString:@"" options:NSCaseInsensitiveSearch range:fullRange];
}
[devowelizedStrings addObject:newString];
};//Block變量賦值結束
}
return 0;
}
傳遞Block對象
在main.m中,調用enumerateObjectsUsingBlocks:並傳入devowelizer,然後輸出去除了元音字母的字符串。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
//
NSArray *originalStrings = @[@"Sauerkraut",@"Raygun",@"Big Nerd Ranch",@"Mississippi"];
NSLog(@"origianl strings:%@",originalStrings);
NSMutableArray *devowelizedStrings = [NSMutableArray array];
NSArray *vowels = @[@"a",@"e",@"i",@"o",@"u"];
//
void (^devowelizer)(id, NSUInteger, BOOL *);
//
devowelizer = ^(id string, NSUInteger i, BOOL *stop){
NSMutableString *newString = [NSMutableString stringWithString:string];
//
for(NSString *s in vowels){
NSRange fullRange = NSMakeRange(0, [newString length]);
[newString replaceOccurrencesOfString:s withString:@"" options:NSCaseInsensitiveSearch range:fullRange];
}
[devowelizedStrings addObject:newString];
};//
//枚舉數組對象,針對每個數組中的對象,執行Block對象devowelizer
[originalStrings enumerateObjectsUsingBlock:devowelizer];
NSLog(@"new strings:%@",devowelizedStrings );
}
return 0;
}
typedef
Block對象的語法可能會比較複雜。typedef可以將某個Block對象類型定義爲一個新的類型。需要注意的是,不能在方法的實現代碼中使用typedef,應該在實現文件的頂部,或者頭文件內使用typedef。
//將Block對象類型定義爲一個新類型
typedef void (^ArrayEnumerationBlock) (id, NSUInteger, BOOL *);
//聲明Block變量
//void (^devowelizer) (id, NSUInteger,BOOL *);
ArrayEnumerationBlock devowelizer;
2、Block對象 VS 其他回調
上一章介紹過兩種回調機制:委託機制和通告機制。這兩種方法可以很好的完成任務,但是回調的設置代碼和回調方法的具體實現無法寫在同一段代碼中。這兩段代碼經常會間隔很遠,甚至會出現在不同的文件中。
然而,通過Block對象,將回調相關的代碼寫在同一代碼段中。這樣閱讀程序比較方便。
3、深入學習Block對象
返回值
^(double dividend, double divisor){
double quotient = dividend / divisor;
return quotient;
}
//在這個示例中,有兩個double類型的實參,返回一個double類型的值。要在變量中保存這個Block,需要聲明一個double類型的變量,然後再將Block賦值給這個變量:
//聲明divBlock變量,這應該是一個Block對象
double (^divBlock)(double,double);
//將Block對象賦給變量
divBlock = ^(double dividend, double divisor){
double quotient = dividend / divisor;
return quotient;
}
//調用,像調用函數一樣調用divBlock
double myQuotient = divBlock(42.0, 12.5);
在Block對象中使用self
爲了避免Block對象捕獲self引起的強引用循環,可以先在Block對象外聲明一個weak指針,然後將這個指針指向Block對象使用的self,最後在Block對象中使用這個新的指針。
__weak BNREmployee *weakSelf = self;//一個弱引用指針
myBlock = ^{
NSLog(@"Employee:%@",weakSelf);
}
現在這個Block對象對BNREMployee實例是弱引用,強引用循環打破了。然而由於是弱引用,所以self指向的對象在Block對象執行的時候可能被釋放。爲了避免這種情況,可以在Block對象中創建一個對self的局部強引用。
__weak BNREmployee *weakSelf = self;//一個弱引用指針
myBlock = ^{
//局部強引用
BNREmployee *innerSelf = weakSelf;
NSLog(@"Employee:%@",weakSelf);
}
修改外部變量
在Block對象中,被捕獲的變量是常數,程序無法修改變量保存的值。
如果需要在Block對象中修改某個外部變量,則可以在聲明相應的外部變量時,在前面加上__block關鍵字。
__block int counter = 0;
void (^counterBlock)() = ^{counter++ ;};
counterBlock();//counter增加1,數值爲1
counterBlock();//counter增加1,數值爲2