其实一直不然懂block这个东西,今天就 一边查资料 一边记录 一边学吧。
传统定义:A block is an anonymous inline collection of code, and sometimes also called a "closure".就是活:block其实一个匿名的内联代码集合体 ,有时也称为“闭包”。
Block从IOS4.0+ 和 Mac OS X 10.6+引进的对C语言的扩展,用来实现匿名函数的特性
这好像是重点:一个函数里定义了个block,这个block可以访问该函数的内部变量。
看一个简单的block代码示例:上代码
- (void) block{
int (^Multiply)(int,int) = ^(int num1, int num2)
{
return num1 * num2;
};
NSLog(@"multiply :%d",Multiply(2,3));
__block int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
multiplier ++;//假如上面的 multiplier 变量没有用 __block 定义的话,编译报错;
return num * multiplier;
};
NSLog(@"myBlock :%d",myBlock(2));
}
通常来说,block都是一些简短代码片段的封装,适用作工作单元,通常用来做并发任务、遍历、以及回调。
比如我们可以在遍历NSArray时做一些事情:直接上代码
- (void)arrayBlock{
NSMutableArray *mArray = [NSMutableArrayarrayWithObjects:@"a",@"b",@"abc",nil];
NSMutableArray *mArrayCount = [NSMutableArrayarrayWithCapacity:1];
[mArray enumerateObjectsWithOptions:NSEnumerationConcurrentusingBlock: ^(id obj,NSUInteger idx,BOOL *stop){
[mArrayCount addObject:[NSNumbernumberWithInt:[obj length]]];
}];
NSLog(@"%@",mArrayCount);
}
打印结果:2013-08-07 11:24:45.980 Block[1744:c07] (
1,
1,
3
)
而在很多框架中,block越来越经常被用作回调函数,取代传统的回调方式,具体看下面几点:
这份文档中提到block的几种适用场合
http://developer.apple.com/library/ios/#featuredarticles/Short_Practical_Guide_Blocks/index.html
和函数一样拥有参数类型
有推断和声明的返回类型
可以捕获它的声明所在相同作用域的状态,可以和其他定义在相同作用域范围的block进行共享修改
你可以拷贝一个 block,甚至可以把它作为可执行路径传递给其他线程(或者在自己的线程内传递给run loop)。编译器和运行时会在整个block生命周期里面为所有block 引用变量保留一个副本。尽管 blocks 在纯 C 和 C++上面可用,但是一个 block也同样是一个 Objective-C 的对象。
Block的用处:
Blocks通常代表一个很小、自包的代码片段。因此它们作为封装的工作单元在并发执行,或在一个集合项上,或当其他操作完成时的回调的时候非常实用。
Blocks 作为传统回调函数的一个实用的替代办法,有以下两个原因:
它们可以让你在调用的地方编写代码实现后面将要执行的操作。
因此 Blocks 通常作为框架方法的参数。
它们允许你访问局部变量。
而不是需要使用一个你想要执行操作时集成所有上下文的信息的数据结构来
进行回调,你可以直接简单的访问局部变量。
Blocks 还支持可变参数(...)。一个没有使用任何参数的 block 必须在参数列表上面用 void 标明。
为了可以在 block 内修改一个变量,你需要使用__block 存储类型修饰符来标识该变量。
看下面几种声明:
void(^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntAndCharWithVoidArguments)(int,char);
void(^arrayOfTenBlockReturningVoidWithIntArgument[10])(int);
__block存储类型
作为一种优化,block存储在栈上面,就像blocks本身一样。如果使用Block_copy拷贝了block 的一个副本(或者在Objective-C 里面给block 发送了一条copy 消息),变量会被拷贝到堆上面。所以一个__block变量的地址可以随时间推移而被更改。
使用__block 的变量有两个限制:它们不能是可变长的数组,并且它们不能是包含有 C99 可变长度的数组变量的数据结构。
使用block作为方法函数的参数,上代码:
NSArray *array = [NSArrayarrayWithObjects: @"A",@"B", @"C", @"A",@"B", @"Z",@"G",@"are", @"Q", nil];
NSSet *filterSet = [NSSet setWithObjects: @"A",@"Z", @"Q", nil];
BOOL (^text)(idobj,NSUInteger idx,BOOL *stop);
text = ^(id obj, NSUInteger idx, BOOL *stop) {
if (idx < 5) {
if ([filterSet containsObject: obj]) {
return YES;
}
}
return NO;
};
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];
NSLog(@"indexes: %@", indexes);
该 block 是内联定义的 ,继续上代码:
__block BOOL found =NO;
NSSet *aSet = [NSSetsetWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];
NSString *string =@"gamma";
[aSet enumerateObjectsUsingBlock:^(id obj,BOOL *stop){
if ([objlocalizedCaseInsensitiveCompare:string] == NSOrderedSame)
{
*stop = YES;
found = YES;
}
}];