block
block封装了一段代码,可以在任何时候执行,block可以作为函数参数或者函数的返回值,而其本身又可以带参数或返回值,所以有时候称block为代码块或代码段。
1.block的定义:这里跟指向函数的指针非常像,但是一般需要使用指向函数的指针的时候都是用block替代,能用block就用block(苹果官方建议)
int (^MyBlock)(int, int);
MyBlock = ^(int a, int b) {
return a + b;
};
实际上可以直接这么写
int (^MyBlock)(int, int) = ^(int a, int b) {
return a + b;
};
定义了一个叫MyBlock的block对象,它带有两个int参数,返回值类型int,等式的右边就是block的具体实现
返回值类型(^block代码块名称)(接受参数类型1,接受参数类型2) = ^(形参1,形参2){
返回值
};
2.block的typedef
语法:与函数的typedef类似
typedef 返回值类型 (^block代码块别名)(参数类型列表);
这里要记住的是 这里的代码块别名指的是类型
例如:
//给无返回值、带2个int类型参数的block类型起别名isBlock
typedef void(^isBlock)(int,int);
//利用别名 定义变量 myBlock,并将代码段赋值给myBlock
isBlock myBlock = ^(int a,int b){
NSLog(@"a + b = %d",a+b);
};
3.三种类型的block
1)NSGlobalBlock,类似函数存放在代码区
定义在函数外的(全局)block是NSGlobalBlock类型的,另外如果函数内部的block没有访问任何函数内部局部变量,那么也是NSGlobalBlock类型的
2)NSStackBlock,存放在栈区,代码块结束后(作为函数返回值)block将无效
在MRC情况下函数内部的block访问局部变量,得到的是栈区
3)NSMallocBlock,存放在堆内存
在MRC情况下,对栈区的block进行copy,才会得到一个堆区的block,要注意的是,对全局block进行copy,不会有任何作用,依然是代码区block
在ARC情况下,访问局部变量,得到的是堆区的block,对堆区的block进行copy,依然是堆区
4.block作为实例变量@property为什么要使用copy
因为在MRC情况下使用block(栈区的block)作为函数返回值,block存放在栈区,代码结束,也就被回收了,返回的是无效的block,同理,作为方法参数,block其实是在堆区指向栈区的一块内存中存放,也存在作用域的问题.在ARC的情况下没有这个内存隐患
1 #import <Foundation/Foundation.h> 2 3 int main(int argc,const char * argv[]){ 4 @autoreleasepool { 5 6 //创建一个block,没有访问函数内部局部变量 7 void (^isBlock1)() = ^(){ 8 NSLog(@"我是没有访问局部变量的block"); 9 }; 10 11 //ARC情况下输出:isblock1的内存地址是:<__NSGlobalBlock__: 0x100001060> 12 //代码区 13 NSLog(@"没有访问局部变量的block内存地址是:%@",isBlock1); 14 15 //MRC情况下输出:isblock1的内存地址是:<__NSGlobalBlock__: 0x100001050> 16 //代码区 17 NSLog(@"没有访问局部变量的block内存地址是:%@",isBlock1); 18 19 int a = 10; 20 21 void (^isBlock2)() = ^(){ 22 NSLog(@"我是访问局部变量的block,%d",a); 23 }; 24 //ARC情况下输出:isblock2的内存地址是:<__NSMallocBlock__: 0x1002067c0> 25 //堆区 26 NSLog(@"访问局部变量的block内存地址是:%@",isBlock2); 27 28 //MRC情况下输出:isblock2的内存地址是:<__NSStackBlock__: 0x7fff5fbff808> 29 //栈区 30 NSLog(@"访问局部变量的block内存地址是:%@",isBlock2); 31 32 //在MRC情况下对刚才访问局部变量的isBlock进行copy操作 33 void (^isBlock3)(); 34 isBlock3 = [isBlock2 copy]; 35 //MRC情况下输出:copy后内存地址是:<__NSMallocBlock__: 0x1002067c0> 36 //堆区 37 NSLog(@"copy后内存地址是:%@",isBlock3); 38 39 } 40 41 return 0; 42 }