用OBJC编程 7 - Working with Blocks
Block 是语言级别的特性。它是一个OBJC的对象,可以被加入容器如NSArray或NSDictionary。它可以捕获所处作用域的数值,非常类似其它语言的closure或者lambda。语法^{
NSLog(@"This is a block");
}
可以像函数指针那样声明一个变量来持有这个blockvoid (^simpleBlock)(void);
simpleBlock = ^{
NSLog(@"This is a block");
}; // 注意这里有一个分号
也可以这样写void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};
调用这个blocksimpleBlock();
带上参数和返回值^double (double firstValue, double secondValue){
return firstValue*secondValue;
}
// ,,,,,,,,,,,
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) { // 返回值类型可以省略
return firstValue*secondValue;
};
double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);
捕获Enclosing Scope内的值,一旦捕获,这个值就不会变化,即便后续改变这个值-(void)testMethod{
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
}
anInteger = 84;
testBlock(); // 仍然输出42
}
使用__block__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84:
testBlock(); // output 84;
// ,,,,,,,,,,,,,
_block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger); // output 42
anInteger = 100;
};
testBlock();
NSLog(@"Value of original variable is now: %i", anInteger); // output 100;
通过参数传递Block,例如实现一个回调-(IBAction)fetchRemoveInformation:(id)sender{
[self showProgressIndicator];
XYZWebTask *task = //,,,
[task beginTaskWithCallbackBlock:^{
[self hideProgressIndicator];
}];
}
// beginTaskWithCallbackBlock 的定义是这样的
-(void)beginTaskWithCallbackBlock:(void)(^)(void))callbackBlock{
//,,,
callbackBlock();
}
最佳实践是将block作为最后一个参数,这样便于阅读。也可以使用typedef简化语法typedef void (^XYZSimpleBlock)(void);
//,,,,,,,,,,,,,,,
XYZSimpleBlock anotherBlock = ^{ /*,,,*/ };
//,,,,,,,,,,,,
-(void)beginFetchWithCallbackBlock:(XYZSimpleBlock)callbackBlock{
//,,,,
callbackBlock();
}
可以将block作为属性@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void); // 必须使用copy
@end
//,,,,,,,,,,,,,,
self.blockProperty = ^{ /* ,,, */ };
self.blockProperty();
避免强引用循环在block里捕获self,诸如在一个callback block里,会引入内存管理问题。block会会维护一个捕获对象的强引用,包括self@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
////////////////////////
@implementation XYZBlockKeeper
-(void)configureBlock{
self.block = ^{
[self doSomething]; // 捕获了一个self的强引用
// 建立了一个强引用循环
}
}
@end
上述代码会产生一个编译警告,为了避免这种情况,最佳实践是捕获一个self的弱引用-(void)configureBlock{
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^ {
[weakSelf doSomething];
};
}
block可以简化枚举(略)block可以简化并发任务(略)