Blocks 可以捕获作用域中的值
- (void)aMethod {
int anInteger = 1;
void (^aBlock)(void) = ^{
//anInteger = 11; //Buildtime error
NSLog(@"anInteger = %i", anInteger);
};
anInteger = 2;
aBlock(); //anInteger = 1
}
变量“anInteger”定义在“aBlock”的外部,但属于相同的作用域,当定义“aBlock”时,捕获了“anInteger”的值。在“aBlock”定义后,即使修改“anInteger”的值,被捕获的值也不会改变。而且在“aBlock”内部也不能修改“anInteger”的值,可以理解为一个 int const 变量。
若一定要修改变量“anInteger”的值,可以使用 __block 存储类型修饰符定义该变量。
__block int anInteger = 1;
void (^aBlock)(void) = ^{
anInteger = 11;
NSLog(@"anInteger = %i", anInteger);
};
anInteger = 2;
aBlock(); //anInteger = 11
使用 __block 修饰变量后,在定义“aBlock”时捕获的不是变量“anInteger”的值而是地址,可以理解为一个 int * const 变量,存储了“anInteger”变量的内存地址,通过地址修改值。
Blocks 可以作为函数和方法的参数
//declare
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;
//invoke
[ary enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//define block
}];
//define (infer)
- (void)enumerateObjectsUsingBlock:(void (^)(id, NSUInteger, BOOL *))block {
NSUInteger idx = 0;
BOOL stop = NO;
for(id obj in self) {
if (stop) {
break;
}
idx = [self indexOfObject:obj];
//invoke block
block(obj, idx, &stop);
}
}
在封装方法的过程中,需要与外部交互,暴露出方法内部的数据给外部进行相应的处理。通过使用 block 实现了封装固定代码,变化的代码由外部提供,减少冗余代码。
Blocks 可以作为函数和方法的返回值
#import <Foundation/Foundation.h>
//加法类
@interface YGAddition: NSObject
//存储计算结果
@property (assign, nonatomic) NSInteger result;
//加上一个值
- (YGAddition *)add:(NSInteger)value;
//功能同上
- (YGAddition *(^)(NSInteger))add;
@end
#import "YGAddition.h"
@implementation YGAddition
- (YGAddition *)add:(NSInteger)value {
self.result += value;
return self;
}
- (YGAddition *(^)(NSInteger))add {
YGAddition *(^rtn)(NSInteger) = ^(NSInteger value) {
self.result += value;
return self;
};
return rtn;
}
@end
//demo
YGAddition *adt = [[YGAddition alloc] init];
adt.result = 1;
//invoke "- (YGAddition *)add:(NSInteger)value"
[[adt add:1] add:-1];
//invoke "- (YGAddition *(^)(NSInteger))add"
adt.add(1).add(-1);
NSLog(@"result = %li", adt.result); //result = 1