---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
代码块
代码块对象(简称为代码块)是对C语言中函数的扩展。除了函数中的代码,代码块还包含变量绑定。代码块有时也被称为闭包(closure)。
代码块包含两种类型的绑定:自动型和托管型。自动绑定使用的是栈中的内存,而托管绑定使用的是通过堆创建的。
因为代码块实际上是由C语言实现的,所以他们在各种以C作为基础的语言内都是有效的,包括Objective-C、C++以及Objective-C++。
代码块在Xcode的GCC和Clang工具中是有效的,但它不属于ANSI的C语言标准。
代码块和函数指针
代码块借鉴了函数指针的用法。所以如果你知道如何声明函数指针,也就知道如何声明一个代码块。与函数指针类似,代码块具有以下特征:
- 返回类型可以手动声明也可以由编译器推倒;
- 具有指定类型的参数列表;
- 拥有名称。
来看一下函数指针的声明。如下:
void (*my_func)(void);
这是简单的函数指针,它不接收参数和没有返回值。只要把*号替换成^,就可以把它转换为一个代码块的定义了。如下:
void (^my_func)(void);
在声明代码块变量和代码块实现的开头位置都要使用幂操作符。与函数中一样,代码块的代码要放在{ }(花括号)中。下面是一个代码块的实例:
int (^square_block)(int number) =
^(int number) {return (number * number);};
int result = square_block(5);
printf(“Result = %d\n”, result);
这个代码块获取了一个整型的参数并返回这个数字的平方。等号前面是代码块的定义,而后面是实现内容。我们可以用如下关系来表示它们:
<returntype> (^blockname)() = ^{printf("Hello Blocks!\n");};
使用代码块
如果你将代码块声明成了一个变量,所以可以像函数一样使用它。如上面:int result = square_block(5); 这行代码并没有幂符号,因为只有在定义代码块的时候才需要使用它,调用时则不需要。
代码块有一个非常酷的特性可以替换原先的函数:代码块可以访问与它相同的(本地)有效范围内声明的变量,也就是说可以访问与它同时创建的有效变量。
int value = 6;
int (^multiply_block)(int number) = ^(int number)
{
return (value * number);
}
int result = multiply_block(7);
printf(“Result = %d\n”, result);
直接使用代码块
使用代码块的时候通常不需要创建一个代码块变量,而是在代码中内联代码块的内容。通常,你会需要一个代码块作为参数的方法或函数。
NSArray *array = [NSArray arrayWithObjects: @“Amir”, @“mishal”, @“Irrum”, @“Adam”, nil];
NSLog(@“Unsorted Array %@”, array);
NSArray *sortedArray = [array sortedArrayUsingComparator: ^(NSString *object1, NSString *object2) {
return [object1 compare: object2];
}];
NSLog(@“Sorted Array %@”, sortedArray);
简单的创建了一个代码块,使用后就不需要它了。
使用typedef关键字
上面长的变量定义语句让人看的有点晕。我们可以用typedef关键字。
typedef double (^MKSampleMultiply2BlockRef)(double c, double d);
上面这行语句定义了一个名为MKSampleMultiply2BlockRef的代码块变量,它包含两个双浮点参数并返回一个双浮点数值。因此,我们可以像下面这样使用变量。
MKSampleMultiply2BlockRef multiply2 = ^(double c, double d)
{
return c * d;
}
printf(“%f, %f”, mutiply2(4, 5), mutiply2(5, 2));
代码块和变量
代码块被声明后会捕捉创建点时的状态。代码块可以访问函数用到的标准类型的变量。
- 全局变量,包括在封闭范围内声明的本地静态变量
- 全局函数
- 封闭范围内的参数
- 函数级别(即,与代码块声明时相同级别)的_block变量。它们是可以修改的变量。
- 封闭范围内的非静态变量会被获取为常量。
- Objective-C的实例变量。
- 代码块内部的本地变量。
本地变量
本地变量就是与代码块在同一范围内声明的变量。我们看下面的一个示例:
typedef double (^MKSampleMultiplyBlockRef)(void);
doub a = 10, b = 20;
MKSampleMultiplyBlockRef multiply = ^(void) {return a * b};
NSLog(@“%@”, multiply());
a = 20;
b = 50;
NSLog(@“%@”, multiply());
第二个NSLog语句会输出什么?1000?答案是200 。因为变量是本地的,代码块会在定义时复制并保存它们的状态。
全局变量
在上面的示例中,我们说过变量与代码块拥有相同的有效范围,可以根据需要把变量标记为静态的(全局的)。
static doub a = 10, b = 20;
MKSampleMultiplyBlockRef multiply = ^(void) {return a * b};
NSLog(@“%@”, multiply());
a = 20;
b = 50;
NSLog(@“%@”, multiply());
参数变量
代码块中的参数变量具有和函数中的参数变量相同的作用。
typedef double (^MKSampleMultilply2BlockRef)(double c, double d);
MKSampleMultiply2BlockRef multiply2 = ^(double c, double d)
{
return c * d;
}
NSLog(@“%f, %f”, mutiply2(4, 5), mutiply2(5, 2));
_block变量
本地变量会被代码块作为常量获取到。如果你想要修改它们的值,必须将它们声明为可修改的。否则,像下面这样,会出现出现错误。
double c = 3;
MKSampleMultiply2BlockRef multiply = ^(double a, double b){ c = a * b; };
编译器会给出警告。我们应该将变量c标记为_block。如下:
_block double c = 3;
MKSampleMultiply2BlockRef multiply = ^(double a, double b){ c = a * b; };
有些变量是不能声明为_block类型的。它们有两个限制:
- 没有长度可变的数组;
- 没有包含可变长度数组的结构体。
代码块内部的本地变量
这些变量和函数中的本地变量具有相同的作用。
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------