Block匿名函数(转载)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Block匿名函数(转载)相关的知识,希望对你有一定的参考价值。
块是Objective-C语言提供的一个强大特性,博主会介绍块语法的意义、块内存管理、怎样在程序中开发块和怎样使用现有API(如Foundation框架)中的块。
简言之,块提供了一种方式,使用这种方式可以创建一组语句(即代码块)并将这些语句赋予一个变量,随后就可以调用这个变量。从这方面看,块与函数方法类似,但除了是可执行代码外,块还含有与堆内存和栈内存绑定的变量。块就是一个实现的闭包(closure),一个允许访问其常规范围之外变量的函数。此外,一个Objective-C块实际上就是一个对象;一个NSObject类的子类,拥有NSObject类的所有相关属性(如可以向块发送消息)。
1.块的语法
在学习使用块编写的过程中,难点之一是掌握块的语法。本段内容详解介绍块语法,并且会通过示例展示块在代码中的作用。
块类型由返回值类型和参数类型列表构成。使用脱字符(^)可以声明块类型的变量。
也许这张图片看客们还不能让各位看客去和C语言的函数做类比记忆,博主带着大家将Block的定义和函数指针类型做对比记忆。
//1.sum函数声明
函数声明:int sum(int a, int b);
函数类型int(int, int);
函数指针类型:int(*)(int, int);
将函数指针类型重命名:typedef int(*FUNP)(int, int);
//2.Block声明
注意:这里只要将函数指针类型标志"*"改为Block语法的标志"^"就是Block语法。
int (^sum)(int, int)
上面博主已经介绍过了,Block是将一个函数的实现赋予Block变量,下面定义函数。
//3.函数定义语法
int sum(int a, int b) {
return a + b;
}
//4.Block定义
把前面的Block变量类型拿过来
int (^sum)(int, int)
将函数的定义赋给Block变量sum
int (^sum)(int, int) = ^int (int a, int b) {
return a + b;
}
注意:
1.后面的函数实现的名字被去掉了,这里赋给Block变量的其实是一个匿名函数。
2.等号右面加了一个Block语法标志”^”不能省略。
这样一个Block语法块、或者叫做匿名函数就创建好了
1.块常量表达式—-没有设置返回值类型的块常量表达式
^int (int addend) {
retutn addend + 1;
}
无需再块定义中为这个块设置返回值类型,因为编译器会从块主题中的return语句推断出返回值的数据类型。
2.不带参数的块常量定义
^ {
NSLog(@"Hello,World!");
}
块语法元素的比较
块语法元素 | 块变量声明 | 块常量表达式 |
---|---|---|
脱字符 | 标识一个块变量声明的开始。脱字符位于变量名称之前,两者都被封装在圆括号中 | 标识一个块变量表达式的开始 |
名称 | 块变量的名称是必选项 | 块常量表达式没有名称 |
返回值类型 | 在块变量声明中返回值类型是必选项。没有返回值的块变量会将返回值声明为void | 从块表达式的语句主题推断出返回值类型。如果块表达式的语句主题中有一个以上的return语句,那么他们的返回值必须为同一类 |
参数 | 在块变量声明中,参数类型列表是必选项。如果块变量没有参数,必须将参数类型列表声明为void | 在块常量表达式中,参数列表是可选项 |
2.块就是闭包
如前面所述,块就是一个实现的闭包,就是一个允许访问在其常规范围外部声明的局部变量的函数。为了理解这些概念,让我们先来了解范围和可见性规则。变量的可见性是指变量在程序的哪个(些)部分中可以被访问,这也称为变量的范围。例如,在C语言函数定义中声明的变量拥有局部范围,这意味着这些变量仅仅在该函数中是可见的和可访问的(注意,函数还可以引用全局变量)。与C语言函数相比,块参数通过以下特性提高了变量的可见性。
- 对词汇范围的支持:这是从封闭范围引用局部变量和参数的特性。
- __block变量:__block关键字可以应用于块外部但仍处于同一词汇范围外的变量。通过该特性可以修改块内部的变量。
- 访问实例变量:在对象的方法实现代码中定义的块可以访问该对象中的实例变量。
- 导入参数 :通过头文件(通过#improt或#include指令)导入的常数变量在块常量表达式中是可见的。
2.1词汇范围
块的一大特性就是支持词汇范围。与之相反,C语言函数无法访问在其定义外部声明的局部变量。
void logValue() {
//错误,对变量myVar进行了非法访问,该变量不在访问范围内
NSLog(@"Variable value %d", myVar);
}
int main(int argc, const char *argv[]) {
int myVar = 10;
logValue();
return 0;
}
块支持词汇范围,因此块常量表达式可以访问在同一词汇范围内声明的变量。此外,一方面,能够定义变量的地方就能够定义块,例如,在函数、方法和其他块中都可以定义块。另一方面、C语言函数无法在其他函数和方法中定义。以下代码可以成功编译和运行,因为变量myVar是在logValueBlock块所在的词汇范围内声明的。
{
int myVar = 10;
void (^logValueBlock)(void) = ^{
NSLog(@"Variable value = %d", myVar);
};
logValueBlock();
}
如以上代码所示,一个块访问了在其定义之外声明的局部变量。尤其是,这些局部变量是在声明块常量表达式之前,在一个封闭范围内被声明(和初始化)的。可以用花括号划定局部范围,此外,还可以嵌套捍卫。一方面,如上面代码所示,变量myVar是定义logValueBlock块的范围内被声明的,而且其声明位于块常量表达式之前,因为可以在这个块常量表达式中使用。另一方面,如果局部变量myVar是在块常量表达式之后声明和初始化的,则块对局部变量的访问是非法的。
{
int myVar = 10;
void (^logValueBlock)(void) = ^{
//错误,词汇范围变量无法重新赋值
myVar = 5;
NSLog(@"Variable value = %d", myVar);
};
logValueBlock();
}
2.2可以修改的__block变量
默认情况下,在块常量表达式中通过词汇范围访问的块局部变量不能修改。使用存储类型修改符__block可以将这些变量切换为读写模式(可以修改)。除了C语言的变长数组(不是由常量表达式表示长度的数组)和含有变长数组的C语言结构之外,可以对Objective-C支持的所有类型使用__block修改符。__block修改符不能与局部变量存储修改符auto、register和static组合使用。
__block int myVar = 10;
void(^incBlock)(int) = ^(int amount) {
myVar += amount;
NSLog(@"New value = %d", myVar);
};
incBlock(5);
以上是关于Block匿名函数(转载)的主要内容,如果未能解决你的问题,请参考以下文章