从最简单的block开始开起,有一些浅显的心得如下:
在main.m文件生成如下代码:
int main(int argc, const char * argv[]) {
void(^blk)(void) = ^{NSLog(@"Block");};
blk();
}
通过命令行翻译(clang -rewrite-objc main.m)
删除不必要代码得到如下的c++文件
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) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_c8_pr2fhjtd5kz0_53s61zxc_400000gn_T_main_c32327_mi_0);
}
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) = ((void (*)())&__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
((blk)->FuncPtr)(blk);
return 0;
}
在block上的代码 翻译后 主要是变成了静态函数__main_block_func_0
从生成的代码上观察主要变成了封装的若干结构体
从上到下依次观察结构体,
__block_impl结构体是系统默认规定的结构体,并不是该代码翻译过来的结构体,结构体内部有isa指针(通常通俗的理解,拥有isa指针都会是一个对象,也就是说block会成为一个对象的可能,但这里不深究) ,观察最后一个变量
void FuncPtr; void 类似于oc中的id类型 (万能指针) 但从系统给出的变量名字可以看出是一个函数指针 也就是说oc中的block转换成多个结构体进行封装的函数指针
也就是说我们可以仿照转换的代码进行构造block
按照生成的代码风格进行 仿造后 得到如下代码:
struct __block_impl {
void *FuncPtr;
};
struct __main_block_impl_0 {
struct __block_impl impl;
__main_block_impl_0(void *fp) {
impl.FuncPtr = fp;
}
};
static void __main_block_func_0() {
NSLog(@"Block");
}
int main(int argc, const char * argv[]) {
struct __main_block_impl_0 s = __main_block_impl_0((void *)__main_block_func_0);
void(*blk)(void) = ((void (*)())&s);
((void (*)())((__block_impl *)blk)->FuncPtr)();
return 0;
}
该代码是在原有代码的基础上 删除了多余结构体变量 尽量做到最简化实现,在main函数上 是保持了翻译后的代码风格,看上去有些乱,在此基础上写了一个更易理解的调用形式如下:
int main(int argc, const char * argv[]) {
struct __main_block_impl_0 s = __main_block_impl_0((void *)__main_block_func_0);
void(*blk)(void) = (void (*)())s.impl.FuncPtr;
blk();
return 0;
}
从上述描述上看,起码最简单的block ,最终也会形成一种函数,只不过是通过函数指针的形式进行调用,综上,可以通俗的理解为
block=函数+若干结构体封装(内部有函数指针变量)
网友评论