Block基础

一个最基本的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++的代码。

你可能感兴趣的:(Block基础)