原文链接:working with block
什么是block
- 块是添加在 c,object-c 和 c++ 语言中的语言级别的形式,它允许你编写一个独特的代码段,这个代码段能够在作为值方法和函数中传递。
- 块是 object-c 的对象,这意味着他们能够被添加到像NASArray或是NSDictionary的集合中.
没有参数和返回值的块
定义一个块
^{
NSLog(@"This is a block");
}
声明块变量
void (^simpleBlock)(void);
块变量赋值
void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};
块变量赋值的简约形式
simpleBlock = ^{
NSLog(@"This is a block");
};
调用块命令
simpleBlock();
有参数和返回值的块
定义一个块
//1.
^ (double firstValue, double secondValue) {
return firstValue * secondValue;
}
//2.
^ double (double firstValue, double secondValue) {
return firstValue * secondValue;
}
声明块变量
double (^multiplyTwoValues)(double, double);
调用块命令
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) {
return firstValue * secondValue;
};
double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);
块的值域
如果你在一个方法中声明了块,他可以捕捉到任何在方法域中可以访问到的值
- (void)testMethod {
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
testBlock();
}
一旦捕获后,即使在捕获后和调用期间改变值,不受影响.块不能够改变初始变量的值,或者是被捕获的值
int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();
//Integer is: 42
__block变量(块变量的改变)
变量和块共享存储空间。变量改变,块内的也改变
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};
anInteger = 84;
testBlock();
//Integer is:84
变量可以在块内被改变
__block int anInteger = 42;
void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
anInteger = 100;
};
testBlock();
NSLog(@"Value of original variable is now: %i", anInteger);
//Integer is: 42
//Value of original variable is now: 100
块作为方法或函数的参数
- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock;
- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock {
...
callbackBlock();
}
- (void)doSomethingWithBlock:(void (^)(double, double))block {
...
block(21.0, 2.0);
}
块应该总是一个方法的最后一个参数
//声明
- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback;
//调用
[self beginTaskWithName:@"MyTask" completion:^{
NSLog(@"The task is complete");
}];
块也用于回调 — 定义了当一个任务结束时将被执行的代码
- (IBAction)fetchRemoteInformation:(id)sender {
[self showProgressIndicator];
XYZWebTask *task = ...
[task beginTaskWithCallbackBlock:^{
[self hideProgressIndicator];
}];
}
定义块的数据类型
typedef void (^XYZSimpleBlock)(void);
XYZSimpleBlock anotherBlock = ^{
...
};
- (void)beginFetchWithCallbackBlock:(XYZSimpleBlock)callbackBlock {
...
callbackBlock();
}
该 complexBlock 变量是指一个块需要另一块作为一个参数(ABLOCK)并返回另一个块
void (^(^complexBlock)(void (^)(void)))(void) = ^ (void (^aBlock)(void)) {
...
return ^{
...
};
};
重写代码使用类型定义使其可读性更高,将块定义成数据类型
XYZSimpleBlock (^betterBlock)(XYZSimpleBlock) = ^ (XYZSimpleBlock aBlock) {
...
return ^{
...
};
};
定义块为属性
@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void); //通常使用copy,why?
@end
self.blockProperty = ^{
...
};
self.blockProperty();
使用块属性声明的类型定义
typedef void (^XYZSimpleBlock)(void);
@interface XYZObject : NSObject
@property (copy) XYZSimpleBlock blockProperty;
@end
Avoid Strong Reference Cycles when Capturing self
Blocks maintain strong references to any captured objects, including self, which means that it’s easy to end up with a strong reference cycle。 block对任何捕获的对象是强引用。
@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end
@implementation XYZBlockKeeper
- (void)configureBlock {
self.block = ^{
[self doSomething]; // capturing a strong reference to self
// creates a strong reference cycle
};
}
...
@end
正确做法如下
- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
// to avoid the reference cycle
}
}
By capturing the weak pointer to self, the block won’t maintain a strong relationship back to the XYZBlockKeeper object. If that object is deallocated before the block is called, the weakSelf pointer will simply be set to nil.