您的位置:首页 > 移动开发 > IOS开发

IOS学习笔记42--Block探究(一)

2013-08-07 17:56 337 查看
其实一直不然懂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除了能够定义参数列表、返回类型外,还能够获取被定义时的词法范围内的状态(比如局部变量),并且在一定条件下(比如使用__block变量)能够修改这些状态。此外,这些可修改的状态在相同词法范围内的多个block之间是共享的,即便出了该词法范围(比如栈展开,出了作用域),仍可以继续共享或者修改这些状态。

通常来说,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作为回调函数,可以使得程序员在写代码更顺畅,不用中途跑到另一个地方写一个回调函数,有时还要考虑这个回调函数放在哪里比较合适。采用block,可以在调用函数时直接写后续处理代码,将其作为参数传递过去,供其任务执行结束时回调。
另一个好处,就是采用block作为回调,可以直接访问局部变量。比如我要在一批用户中修改一个用户的name,修改完成后通过回调更新对应用户的单元格UI。这时候我需要知道对应用户单元格的index,如果采用传统回调方式,要么需要将index带过去,回调时再回传过来;要么通过外部作用域记录当前操作单元格的index(这限制了一次只能修改一个用户的name);要么遍历找到对应用户。而使用block,则可以直接访问单元格的index。

这份文档中提到block的几种适用场合 http://developer.apple.com/library/ios/#featuredarticles/Short_Practical_Guide_Blocks/index.html
任务完成时回调处理
消息监听回调处理
错误回调处理
枚举回调
视图动画、变换
排序

Block功能:
和函数一样拥有参数类型
有推断和声明的返回类型
可以捕获它的声明所在相同作用域的状态,可以和其他定义在相同作用域范围的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;
}
}];
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: