定义
void (^名称)(参数) = ^{
};
使用
名称();
参考示例
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
int num = 1;
void (^block)(void) = ^{
NSLog(@"打印了 num = %d",num);
NSLog(@"这个是 block");
};
block();
}
return 0;
}
原理解析
首先我们将上面的代码生成 cpp 文件看一下上面的代码会将我们的内容编译成什么样子
编译命令:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
最终生成内容如下
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_0);
int num = 1;
void (*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, num));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
}
return 0;
}
关键结构体有下面内容
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int num;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _num, int flags=0) : num(_num) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int num = __cself->num; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_1,num);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_dv_nb1mrprn3kj3cnk3tts4918w0000gn_T_main_f590b1_mi_2);
}
可以发现我们最后的 block 定义其实是生成了一个结构体,并通过结构体的构造函数传递了三个参数。
&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, num)
参数一:__main_block_func_0 则是我们实际执行的代码
参数二: __main_block_desc_0_DATA 是 block 的信息记录,Block_size 记录了 block 的大小。
参数三:num 则是我们访问的外部变量,赋值给了 block 内的变量 num
而且通过观察 __main_block_impl_0
,我们可以发现此处也是生成了 isa 指针的,所以我们可以确认我们的 block 是一个对象。并且在构造函数中将传入的代码执行地址传递给了 impl 的 funcPtr, 在下面我们调用 block() 的时候实际也就是调用的 (impl->funcPtr)(num)
网友评论