在Object-C中,块的概念和我们熟知的函数式编程中的块概念一致,就是一个独立的逻辑处理单元,据说苹果公司为C,C++和Object-C都扩充了支持块的语法。苹果的系统是在Mac OSX10.6,iOS4.0以后支持块的。
在Object-C中,块被当做一个对象来处理,这个对象可以:
[list]
[*]有自己的局部变量
[*]可以传入参数
[*]有返回值
[*]可以访问自己定义时的上下文变量
[*]可以修改自己定义时特定的上下文变量
[*]作为参数传递给其它函数
[/list]
在引入块特性之后,iOS4.0以后,很多新的API都使用了块做为参数来作为某个操作完成之后的回调。下面就来看一个例子:
这段代码的功能是在一个Dictionary中找到指定位置的玩家。代码中调用了SDK中NSDictionary类的方法:
该方法使用了一个块作为参数,表示遍历Dictionary中的每个对象时做的操作,以及什么时候停止遍历。
在例子代码中,还可以看到一个块的结构,块的定义分4部分:
[list]
[*]'void'表示返回值为空;
[*]'(^)'表示接下来定义的是一个块;
[*]'(id key, id obj, BOOL *stop)'表示该块接受三个参数,他们的类型分别为对象,对象和布尔类型;
[*]'{…}'中的内容表示块的具体处理逻辑;
[/list]
苹果官网上的图是这个样子的:[img]http://developer.apple.com/library/ios/documentation/cocoa/conceptual/Blocks/Art/blocks.jpg[/img]
另外,代码中访问了方法的参数position,表示块可以访问自己定义时的上下文中的变量。
除此之外,块的代码中对上下文中的变量player进行了修改,因此在定义player变量时使用了'__block'关键字,表示该变量可以在块中修改。如果不加该关键字,编译器会报错“Assignment of read-only variable 'player'”。这是因为代码块内使用的是变量的副本,它是堆栈里的一个常量。这些变量在代码块中是不可改变的。。
其实,块从本质上来说是一个闭包,即其拥有代码逻辑和运行该段代码逻辑需要的变量。这一切在定义代码时就已经确定,因此,一个块在定义时访问了某个上文变量,即使之后该上下文变量发生了变化,块中仍然使用是定义时的值,可以认为块只是在定义的时候拷贝了一个变量值到自己的作用域。定义完之后,和原来的那个上下文变量就没有关系了。
在Object-C中,块被当做一个对象来处理,这个对象可以:
[list]
[*]有自己的局部变量
[*]可以传入参数
[*]有返回值
[*]可以访问自己定义时的上下文变量
[*]可以修改自己定义时特定的上下文变量
[*]作为参数传递给其它函数
[/list]
在引入块特性之后,iOS4.0以后,很多新的API都使用了块做为参数来作为某个操作完成之后的回调。下面就来看一个例子:
- (Player *)playerAtPosition:(PlayerPosition)position {
__block Player *player;
[_players enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
player = obj;
if (player.position == position)
*stop = YES;
else
player = nil;
}];
return player;
}
这段代码的功能是在一个Dictionary中找到指定位置的玩家。代码中调用了SDK中NSDictionary类的方法:
- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);
该方法使用了一个块作为参数,表示遍历Dictionary中的每个对象时做的操作,以及什么时候停止遍历。
在例子代码中,还可以看到一个块的结构,块的定义分4部分:
[list]
[*]'void'表示返回值为空;
[*]'(^)'表示接下来定义的是一个块;
[*]'(id key, id obj, BOOL *stop)'表示该块接受三个参数,他们的类型分别为对象,对象和布尔类型;
[*]'{…}'中的内容表示块的具体处理逻辑;
[/list]
苹果官网上的图是这个样子的:[img]http://developer.apple.com/library/ios/documentation/cocoa/conceptual/Blocks/Art/blocks.jpg[/img]
另外,代码中访问了方法的参数position,表示块可以访问自己定义时的上下文中的变量。
除此之外,块的代码中对上下文中的变量player进行了修改,因此在定义player变量时使用了'__block'关键字,表示该变量可以在块中修改。如果不加该关键字,编译器会报错“Assignment of read-only variable 'player'”。这是因为代码块内使用的是变量的副本,它是堆栈里的一个常量。这些变量在代码块中是不可改变的。。
其实,块从本质上来说是一个闭包,即其拥有代码逻辑和运行该段代码逻辑需要的变量。这一切在定义代码时就已经确定,因此,一个块在定义时访问了某个上文变量,即使之后该上下文变量发生了变化,块中仍然使用是定义时的值,可以认为块只是在定义的时候拷贝了一个变量值到自己的作用域。定义完之后,和原来的那个上下文变量就没有关系了。
NSDate *date = [NSDate date];
void (^time)(void) = ^ {
NSLog(@"The date and time is %@", date);
};
time();
NSLog(@"The date and time is %@", date);
sleep(10);
date = [NSDate date];
NSLog(@"The date and time is %@", date);//返回5秒后的新时间
time();//仍然返回上一次的时间