Blocks用一句话概括就是带有自动变量的匿名函数.
首先先创建一个简单的无参数无返回值的block。
int main(){
void (^blk)(void) = ^{
printf("Block\n");
};
blk();
return 0;
}
在main函数中创建一个简单的block,block中是一个简单的printf;
然后通过clang(LLVM编译器)转换为我们可读源代码的功能;
通过命令clang -rewrite-objc 源代码文件名
然后获得了转换后的Block语法。
转换后的源代码文件有数百行的代码,不用管其他,我们只需要翻到文件的最下边,也就是下图中的位置:
首先,先寻找到源代码中block的位置,也就是main函数所在的位置,图中可以清晰的看到,然后来看main函数中的代码:
编译后的代码:
void (*blk)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
接着我们来简化一下,去掉转换的部分,具体如下:
struct __main_block_impl_0 tmp = __main_block_impl_0(__main_block_func_0,&__main_block_desc_0_DATA);
struct __main_block_impl_0 blk = &tmp;
这段代码等于__main_block_impl_0结构体实例的指针变量赋给变量blk,
也就是说源代码中的Block就是__main_block_impl_0结构体指针产生的自动变量。
接下里看一下这段代码:
__main_block_impl_0(__main_block_func_0,&__main_block_desc_0_DATA);
第一个参数是由Block语法转换的的C语言函数指针,第二个参数是作为静态全局变量初始化的__main_block_desc_0的结构体指针。
首先看第一个参数的这个函数指针:
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("Block\n");
}
通过这段代码可以看出,Blocks使用的匿名函数实际上被作为了简单的C语言函数来处理了;
然后看一下传的参数struct __main_block_impl_0 *__cself;
这个__main_block_impl_0结构体的指针__cself相当于Objectice-C中的self;
然后是struct __main_block_impl_0这个结构体的声明,如下:
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
}
然后分别看一看其中的结构体,首先是第一个成员变量impl,来看一下__block_impl结构体的声明。
struct __block_impl{
void * isa;
int Flags;
int Reserved;
void * FucnPtr;
};
从其名称可以看出某些标志、今后版本升级所需的区域以及函数指针。
然后是__main_block_desc_0结构体的声明;
static struct __main_block_desc_0{
size_t reserved;
size_t Block_sized;
};
这些也如同其成员名称所示,其结构为今后版本升级所需区域和block的大小。
接下来就要看一看初始化含有这些结构体的__main_block_impl_0结构体的构造函数。
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
以上就是无变量截获无返回值的block初始化的源代码。