1、block本质是什么?
- (void)testBlock {
void (^block1)(void) = ^(){
NSLog(@"hello");
};
NSLog(@"%@",[block1 class]);
NSLog(@"%@",[[block1 class] superclass]);
NSLog(@"%@",[[[block1 class] superclass] superclass]);
}
打印结果:
2022-01-01 06:27:55.056968+0800 Interview01-kvo[43991:11810676] NSGlobalBlock
2022-01-01 06:27:55.057261+0800 Interview01-kvo[43991:11810676] NSBlock
2022-01-01 06:27:55.057430+0800 Interview01-kvo[43991:11810676] NSObject
所以block本质是一个OC对象。
2、block的类型
- (void)testBlock {
int age = 10;
void (^block1)(void) = ^(){
NSLog(@"hello");
};
void (^block2)(void) = ^(){
NSLog(@"hello-%d",age);
};
NSLog(@"%@ %@ %@",[block1 class], [block2 class], [^{
NSLog(@"%d",age);
} class]);
}
打印结果共3种:
NSGlobalBlock : 全局的 ,条件–>没有访问auto变量的
NSStackBlock:栈里面的 ,条件 --> 访问了auto变量的
NSMallocBlock : 堆里面的,条件 —> NSStackBlock调用了copy
- 关闭ARC
- 搜索:automatic ref–> 设置为no
- 新建命令行项目,关闭ARC后
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 10;
void (^block1)(void) = ^(){
NSLog(@"hello");
};
void (^block2)(void) = ^(){
NSLog(@"hello-%d",age);
};
NSLog(@"%@ %@ %@",[block1 class], [block2 class], [^{
NSLog(@"%d",age);
} class]);
}
return 0;
}
打印结果:
2022-01-01 06:57:01.439787+0800 block[44204:11829604] NSGlobalBlock
NSStackBlock
NSStackBlock
Program ended with exit code: 0
关闭ARC后,可以看到,block2是访问了auto变量,类型为stack
3、重点研究stack类型
- Global类型没太大意义,完全可以用一个普通的函数代替。
- 所以这里重点研究stack类型。
- 先看下下面这段代码会打印什么(MRC环境)
#import <Foundation/Foundation.h>
void (^block)(void);
void test() {
int age = 10;
block = ^{
NSLog(@"hello ---- %d",age);
};
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
test();
block();
}
return 0;
}
- 先看下C++代码(点我查看转换C++代码方式)
// 第一步来到这里
void test() {
int age = 10;
block = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, age));
}
// 第二步会来到这里
struct __test_block_impl_0 {
struct __block_impl impl;
struct __test_block_desc_0* Desc;
int age; // 函数作用域结束后,栈里面的age的值被释放了
__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
// 第三步会来到这里
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {
int age = __cself->age; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_qw_rxjvg1rx6hs778r_253ckdt40000gn_T_main_23a55d_mi_0,age);
}
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
test();
// 第四步来到这里
// test()方法执行完,函数作用域释放了
// 因此,test()函数的栈此刻已经被释放了
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
// 所以,最终打印结果是:
// 2022-01-01 07:12:01.415275+0800 block[44249:11837159] hello ---- -272632584
}
return 0;
}
- 将以上代码改动下
void (^block)(void);
void test() {
int age = 10;
block = [^{
NSLog(@"hello ---- %d",age);
} copy]; // 增加copy
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
test();
block();
}
return 0;
}
- 此刻将block拷贝到内存中
- 因此打印结果是
hello ---- 10
而block的类型也成为malloc类型