block代码块是OC的一个特性,除了可执行的代码外,还可能包含变量的自动绑定(栈),或内存托管(堆)。所以一个block维护一个状态集(数据),可以在任何时候执行。block用来作为回调特别有用。
block可以作为函数参数或者函数的返回值,而本身又可以带输入参数或返回值。在多线程,异步任务,集合遍历,接口回调等地方用得比较多。使用标识符^.。为了性能,block都是分配在栈stack上面的,它的作用域就是当前函数。
我们来说说block和函数的相似性:
(1)可以保存代码;
(2)有返回值;
(3)有形参;
(4)调用方式一样;
下面我们使用代码来演示一下block的用法:
#import <Foundation/Foundation.h> //声明一个闭包; //没有返回值,没有输入参数; void (^one) (void); //有返回值,没有输入参数; int (^two) (void); //没有返回值,有输入参数; void (^three) (int); //有返回值,有输入参数; int (^four) (int ,int); int main(int argc, const char * argv[]) { @autoreleasepool { //定义闭包函数; one = ^(void){ NSLog(@"执行了one"); }; two = ^(void){ NSLog(@"执行了two"); return 2; }; three = ^(int a){ NSLog(@"执行了three"); }; four = ^(int a,int b){ NSLog(@"执行了four"); return a + b; }; //调用闭包函数; one(); two(); three(1); four(2,3); NSLog(@"%d",two()); NSLog(@"%d",four(2,3)); } return 0; }输出结果如下:
同样,我们可以在声明的时候直接定义block,示例如下:
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { //我也可以直接在这里声明的时候进行定义; void(^block)(int a) = ^(int a){ NSLog(@"%d",a); }; block(3); } return 0; }
输出结果如下:
block非常重要的一个功能就是进行值捕获。请看一下示例代码:此时我们只能捕获num的值,不能去修改它,因为这是一个值类型,进行的是值传递。
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { //Block值捕获 int num = 10; void(^myBlock)(void) = ^(void){ //我们可以在block内部访问到外部的变量,但是不能修改; NSLog(@"num = %d",num); }; myBlock(); } return 0; }
但是如果因为项目实际需要,需要在block内部修改外部变量的值,那么就可以使用__block关键字修饰变量,示例代码如下:此时的这个变量就变成了引用类型。在block内就可以修改它的值。
但是请注意,只要没对block进行copy操作,block就一直在在stack中,要想延长block的作用域,就可以进行copy操作,apple提供的接口是Block_Copy()方法,将block复制到heap中。
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { //Block值捕获 __block int num = 10; void(^myBlock)(void) = ^(void){ //我们可以在block内部访问到外部的变量,但是不能修改; NSLog(@"num = %d",num); num = 20;//修改外部变量的值; }; myBlock(); NSLog(@"numnum = %d",num); } return 0; }
github主页:https://github.com/chenyufeng1991 。欢迎大家访问!