黑马程序员_OC中的代码块学习

---------------------- 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培训、期待与您交流! ----------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值