background image

声明函数一样,需要包含返回值的类型,以及参数的类型,这样编译器才能安全的进行强
制类型转换。插入符

(^)跟指针(例如 int *aPointer)前面的星号(*)类似——只是在声明的时候

需要使用,之后用法跟普通的变量一样。
    block 的定义本质上跟函数一样——只不过不需要函数名。block 以签名字符串开始:
^double(double rate, double time)标示返回一个 double,以及接收两个同样为 double 的参数
(如果不需要返回值,可以忽略掉)。在签名后面是一个大括弧({}),在这个括弧里面可以编
写任意的语句代码,这跟普通的函数一样。
    当把 block 赋值给 distanceFromRateAndTime 后,我们就可以像调用函数一样调用这个变
量了。
    不带参数的 Block
    如果 block 不需要任何的参数,那么可以忽略掉参数列表。另外,在定义 block 的时候,
返回值的类型也是可选的,所以这样情况下,

block 可以简写为^ { … }:

double (^randomPercent)(void) = ^ { 
    return (double)arc4random() / 4294967295; 
}; 
NSLog(@"Gas tank is %.1f%% full", 
      randomPercent() * 100); 
    在上面的代码中,利用内置的 arc4random()方法返回一个 32 位的整型随机数——为了获

0-1 之间的一个值,通过除以 arc4random()方法能够获取到的最大值(4294967295)。 

    到现在为止,block 看起来可能有点像利用一种复杂的方式来定义一个方法。事实上,
block 是被设计为闭包的(closure)——这就提供了一种新的、令人兴奋的编程方式。
    Block 的闭包性(closure)
    在 block 内部,可以像普通函数一样访问数据:局部变量、传递给 block 的参数,全局变

/函数。并且由于 block 具有闭包性,所以还能访问非局部变量(non-local variable)。非局部

变量定义在

block 之外,但是在 block 内部有它的作用域。例如,getFullCarName 可以使用

定义在

block 前面的 make 变量:

NSString *make = @"Honda"; 
NSString *(^getFullCarName)(NSString *) = ^(NSString *model) { 
    return [make stringByAppendingFormat:@" %@", model]; 
}; 
NSLog(@"%@", getFullCarName(@"Accord"));    // Honda Accord 
    非局部变量会以 const 变量被拷贝并存储到 block 中,也就是说 block 对其是只读的。如果
尝试在

block 内部给 make 变量赋值,会抛出编译器错误。

    以 const 拷贝的方式访问非局部变量,意味着 block 实际上并不是真正的访问了非局部变

——只不过在 block 中创建了非局部变量的一个快照。当定义 block 时,无论非局部变量

的值是什么,都将被冻结,并且

block 会一直使用这个值,即使在之后的代码中修改了非

局部变量的值。下面通过代码来看看,在创建好

block 之后,修改 make 变量的值,会发生

什么:
NSString *make = @"Honda"; 
NSString *(^getFullCarName)(NSString *) = ^(NSString *model) { 
    return [make stringByAppendingFormat:@" %@", model]; 
}; 
NSLog(@"%@", getFullCarName(@"Accord"));    // Honda Accord   
// Try changing the non-local variable (it won't change the block)