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