Block的实质:函数
#import <Foundation/Foundation.h> int main() { void(^blk)(void)=^{printf("Block");}; blk(); return 0; }
使用clang将该block转换。spa
clang -rewrite-objc 源代码文件
转换后造成的block文件是:指针
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
struct __main_block_impl_0 {code
struct __block_impl impl;对象
struct __main_block_desc_0* Desc;blog
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {it
impl.isa = &_NSConcreteStackBlock;io
impl.Flags = flags;class
impl.FuncPtr = fp;import
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("Block");}
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() {
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);
return 0;
}
下面咱们就来具体分析一下这些源代码:
首先咱们看到
^{printf("Block");};
转换后称为
static void __main_block_func_0(struct __main_block_impl_0 *__cself) { printf("Block");}
如上所示的,block使用的匿名函数,其实被转换成c语言函数处理,,该函数中 的_cself是_main_block_func_0结构体的指针。
struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0* Desc;
具备两个成员变量,_block_impld 代码以下:
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
第二个成员变量是
__main_block_desc_0:其代码以下:
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
}
这个包含了从此版本升级所需的区域以及block的大小。
下面咱们来看一下初始化含有这些数据的结构体的代码:
__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; }
在这里面NSConcreteStackBlock用来初始化,接下来咱们对构造函数的调用:
void(*blk)(void)=((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
由于转换太多实在太难以理解,因此咱们去掉转换的部分,这样获得的结果是:
struct _main_block_impl_0 tmp=_main_block_impl_0(_main_block_func_0,&_main_block_desc_DATA); struct _main_block_impl_0 *blk=&tmp;
这样一来咱们能够清楚的看到,
void(^blk)(void)=^{printf("Block");};
这个语句的实现了_main_block_impl_0的两个变量,一个功能函数,一个desc,将block语法生成的block类型对象再赋值给blk,至关于将实例的指针赋值给blk,_main_block_desc_DATA主要是对_main_block_impl_0的结构体实例的大小进行初始化.
blk();
这部分代码转换成为了
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
咱们同样去掉转换的部分获得:
(*blk)->impl.Funcptr(blk)
这实际上是最简单的函数指针调用函数,正如咱们刚才确认的那样,在调用函数中咱们看出block是做为参数进行传递的。
那么到底什么是NSConcreteStackBlock呢?
为了理解他首先咱们须要理解oc类和对象的实质,其实,所谓的block就是对象,“id”这一变量用于存储oc对象,NSConcreteStackBlock就至关于c结构体实例,将block做为oc对象处理时,该类的信息就放置于NSConcreteStackBlock处。