闭包(Closure)
闭包就是一个函数,或者一个指向函数的指针,加上这个函数执行的非局部变量。
说的通俗一点,就是闭包允许一个函数访问声明该函数运行上下文中的变量,甚至可以访问不同运行上文中的变量。
function funA(callback){
alert(callback());
}
function funB(){
var str = “Hello World”; // 函数funB的局部变量,函数funA的非局部变量
funA(
function(){
return str;
}
);
}
按常规思维来说,变量str是函数funB的局部变量,作用域只在函数funB中,函数funA是无法访问到str的。
block实际上就是Objective-C语言对闭包的实现。
block的原型及定义
我们来看看block的原型:
NSString * (^myBlock)(int);//声明了一个block(^)原型,名字叫做myBlock,包含一个int型的参数,返回值为NSString类型的指针。
myBlock = ^(int paramA)
{
return [NSString stringWithFormate:@“passed number :%i”,paramA];
}
myBlock(7);
由于block数据类型的语法会降低整个代码的阅读性,所以常使用typedef来定义block类型.
如:
typedef NSString * (^myFirstName)(NSString *);
typedef NSString * (^myUserInfo)(NSString *);
@interface Person:NSObj
- (NSString *)getPersonInfo:(myFirstName)name andInfo:(myUserInfo)info;
@end
// .h
-(void) testBlock:( NSString * ( ^ )( int ) )myBlock;
// .m
-(void) testBlock:( NSString * ( ^ )( int ) )myBlock
{
NSLog(@”Block returned: %@”, myBlock(7) );
}
由于Objective-C是强制类型语言,所以作为函数参数的block也必须要指定返回值的类型,以及相关参数类型。
闭包性
上文说过,block实际是Objc对闭包的实现
import void logBlock( int ( ^ theBlock )( void ) )
{
NSLog( @”Closure var X: %i”, theBlock() );
}
int main( void )
{
NSAutoreleasePool * pool;
int ( ^ myBlock )( void );
int x;
pool = [ [ NSAutoreleasePool alloc ] init ];
x = 42;
myBlock = ^( void )
{
return x;
};
logBlock( myBlock );
[ pool release ];
return EXIT_SUCCESS;
}
block中变量的复制与修改
对于block外的变量引用,block默认是将其复制到其数据结构中来实现访问的,如下图:
通过block进行闭包的变量是const的。也就是说不能在block中直接修改这些变量。来看看当block试着增加x的值时,会发生什么:
myBlock = ^( void )
{
x++;
return x;
};
编译器会报错,表明在block中变量x是只读的。
有时候确实需要在block中处理变量,怎么办?别着急,我们可以用__block关键字来声明变量,这样就可以在block中修改变量了。
基于之前的代码,给x变量添加__block关键字,如下:
代码如下:
__block int x;
对于用__block修饰的外部变量引用,block是复制其引用地址来实现访问的
仅当self对象持有block对象的引用,而block当中又直接访问了self时,才会造成循环引用,只是在block中使用self的话是没有关系的。