首先先写一个最简单的block,代码如下
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
void(^blk)() = ^{printf("test1\n");};
blk();
}
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
//我们自己写的代码转换后如下
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__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;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("test1\n");}
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)};
int main(int argc, const char * argv[]) {
void(*blk)() = ((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);
}
__main_block_impl_0
从主函数main中可以看到blk是一个函数指针,指向了一个__main_block_impl_0的结构体地址,其中的__block_impl又是一个结构体,结构体中有四个字段,第一个字段void *isa,说明其可以成员一个OC对象,第四个字段FuncPtr,从名字就可以猜出,它是一个函数指针,
__main_block_impl_0 这个结构体命名意思就是main函数中第0个block的implementation,如果在别的函数中定义并实现block,如test()函数,其对应的结构体就是__test_block_impl_0...
__main_block_impl_0结构体中写了一个带参的构造函数,用来初始化成员变量,
第一个参数传入的是block实际执行代码所在的函数的地址,当block真正被执行时,实际上就是调了这个函数,
第二个参数传入的block的描述结构体,这个结构体在声明结束时就创建一个唯一的desc,这个desc包含了block的大小,以及复制各析构block时需要额外调用的函数(copy,dispose)//注,这个在使用__block变量时,对block进行copy操作,并会生成这两个字段,
由此一个__main_block_impl_o结构体便生成了,主函数main,最后调用,其转换过程如下,将blk函数指针强转为__block_impl指针,然后取其执行函数指针,然后将此指针类型强转为一个无返回值,并接受一个__block_impl*参数的函数指针,并调用这个函数指针,传入强转为__block_impl*类型的blk,至此即完成了block的调用
由于转换较为复杂,下面我间接写一个转换中间代码
typedef void(*BLOCK)(void)//无参无返回值的函数指针
typedef void(*BLOCKIMP)(struct *__block_impl) //无返回值,带一个结构体指针
void *fp = (void *)__main_block_func_0 //取block执行函数地址
__main_block_desc_0 *desc = &__main_block_desc_0_DATA //取block描述结构体
__main_block_impl_0 tmp = __main_block_impl_0( fp, desc); //构造一个__main_block_impl_0结构体
BLOCK blk = (BLOCK)&tmp; //取__main_block_impl_0结构体的地址,然后将其强转为一个无参无返回值的函数指针
__block_impl *blktmp = (__block_impl*)blk;//将blk强转为__block_impl类型,目的是取其执行函数地址
BLOCKIMP blkimp = (BLOCKIMP) blktmp->FuncPtr;//取其执行函数地址,然后强转为一个无返回值,带一个结构体指针
blkimp(blktmp)//函数调用
至此这个调用就完成了