一:什么事Block
Block 是将函数及其执行上下文封装起来的对象。
基本使用:
@property(nonatomic, copy)void(^dismissBlock)(void);
@property(nonatomic, copy)void(^dismissBlock2)(UIView *view);
void (^logBlock)(NSString *)=^(NSString *paramStr){
};
在方法中生命
- (void)getMyBlock:(void(^)(int aa,int bb))myBlock;
typedef 返回类型(^block名)(参数类型 [参数名可选]);
typedef void(^MyBlock)(void);
@property(nonatomic, copy) MyBlock myBlock;
二:Block变量截获
1、局部变量截获 是值截获。 比如:
NSInteger num = 3;
NSInteger(^block)(NSInteger) = ^NSInteger(NSInteger n){
return num *n;
};
num = 1;
NSLog(@"%zd",block(2));
这里的输出是 6 而不是 2,原因就是对局部变量 num 的截获是值截获。 同样,在 block 里如果修改变量 num,也是无效的,甚至编译器会报错。
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1",@"2", nil];
void(^block)(void) = ^{
NSLog(@"%@",arr);
[arr addObject:@"4"];
};
[arr addObject:@"3"];
arr = nil;
block();
打印为 1,2,3 局部对象变量也是一样,截获的是值,而不是指针,在外部将其置为 nil,对 block 没有影响,而该对象调 用方法会影响
2、局部静态变量截获 是指针截获。
static NSInteger num = 3;
NSInteger(^block)(NSInteger) = ^NSInteger(NSInteger n){
return num *n;
};
num = 1;
NSLog(@"%zd",block(2));
输出为 2,意味着 num = 1 这里的修改 num 值是有效的,即是指针截获。 同样,在 block 里去修改变量 m,也是有效的。
3、全局变量,静态全局变量截获:不截获,直接取值。
Block 的几种形式
- 分为全局 Block(_NSConcreteGlobalBlock)、栈 Block(_NSConcreteStackBlock)、堆 Block(_NSConcreteMallocBlock)三种形式
- 1、不使用外部变量的 block 是全局 block
NSLog(@"%@",[^{
NSLog(@"globalBlock");
} class]);
- 2、使用外部变量并且未进行 copy 操作的 block 是栈 block
NSInteger num = 10;
NSLog(@"%@",[^{
NSLog(@"%zd",num);
} class]);
输出为stackBlock
__block底层实现原理
总结:加入了__block的表示后,栈中的指针地址永久的被copy到堆中了,不加入__block时候,只是在block内部时候会被暂时的从栈中被copy到堆中,等block结束后又回到栈中了,因为block对象布局中有copy方法,所以可以进行copy操作
- __block可以用于解决block内部无法修改auto变量值的问题
- __block不能修饰全局变量、静态变量(static)
- 编译器会将__block变量包装成一个对象