一个最基本的block
void (^block)(void) = ^(void){
NSLog(@"这是一个无参数无返回值的block");
};
block();//block的灵活性
这边有个思考,如上的block是在储存的哪个区域?
如果没有深究,凭经验可以说它存在常量区或栈区,因为当前block只是临时变量。
实际上block存在堆区,因为在当前的ARC环境下,block一旦定义出来,编译器就会自动把栈上的block copy到堆里面。
这边再思考一下,block是用什么修饰呢?你可能说copy,那strong是否可以呢?其实strong也是可以的,在当前的arc下,其实已经没有什么区别。
block的分类
首先了解一下几个存储区域:
- 代码段:写的代码都存在这边
- 数据区(常量区):存放全局变量,
NSGlobalBlock
存放在这边 - 栈区:存放局部变量,不需要程序员管理,系统自动分配,自动销毁,
NSStackBlock
存放在这 - 堆区:存放我们自己alloc出来的对象,动态分配内存,需要程序员自己申请内存,自己管理,
NSMallocBlock
存放在这
// -| NSGlobalBlock
// 没有引用auto变量
void (^block)(void) = ^(void){
NSLog(@"没有引用auto变量");
}
NSLog(@"%@",block); //这边用%@ --> block是一个对象
// -| NSStackBlock
// 这边需要MRC环境
// 访问了auto变量
int a = 10; // -->栈区
void (^block)(void) = ^(void){
NSLog(@"访问了auto变量 %d",a);
}
NSLog(@"%@",block);
// -| NSMallocBlock
// ARC环境Xcode帮我们处理成了堆block
// 防止出现释放了还去访问导致野指针crash
int a = 10; // -->栈区
void (^block)(void) = ^(void){
NSLog(@"ARC环境 访问了auto变量 %d",a);
}
NSLog(@"%@",block);
总结:
Block类型 环境 内存 拷贝 NSGlobalBlock 没有访问auto变量 数据区 什么也不做 NSStackBlock 访问auto变量 栈 从栈复制到堆 NSMallocBlock NSStackBlock调用了copy 堆 引用计数增加 在ARC环境下,编译器会自动将栈上的block copy到堆上
block的使用——链式编程
block当作函数的返回值
- (void)viewDidLoad
{
self.getSomeString(@"后被处理");
}
- (void(^)(NSString *))getSomeString
{
void(^block)(NSString *) = ^(NSString *sting){
NSLog(@"这边进行一系列处理 %@",sting);
};
NSLog(@"这边会被先调用");
return block;
}
block当作函数的参数
异步性:比如AFN的successBlock和failBlock
- (void)viewDidLoad
{
[self request:^(NSString *string) {
NSLog(@"%@",string);
}];
}
- (void)request:(void(^)(NSString* string))block
{
block(@"异步处理一些问题");
}
block当作一个参数
灵活性:保存一段代码块,在任何想用的地方去调用实现
block的变量截获
1、局部变量截获,是值的截获
int num = 10;
void(^block)(void) = ^(void){
NSLog(@"num = %d",num);
};
num = 20;
block();
这里num
的打印值为10,原因就是对局部变量的截获是值截获。
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1",@"2",nil];
void(^block)(void) = ^(void){
NSLog(@"%@",arr);
[arr addObject:@"4"];
};
[arr addObject:@"3"];
arr = nil;
block();
这里的打印为1,2,3,局部对象变量的截获也是一样,是截获的值,而不是指针,在外部将其置nil
也对block
没有影响,但是对象调用方法
会影响
2、局部静态变量截获,是指针截获
static int num = 10;
void(^block)(void) = ^(void){
NSLog(@"num = %d",num);
};
num = 20;
block();
这里num
的打印值为20,意味着num = 20
修改有效的,即是指针截获,同样,在block里去修改变量num
也是有效的。
3、全局变量,静态全局变量block是不截获的,直接进行访问
具体的可以通过通过命令clang -rewrite-objc xxx.m
生成.cpp
文件,或者通过xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-9.0.0 XX.m
将.m
文件转成 .cpp
文件,查看c++
的代码。