首先是block结构体的实现:
[cpp]
#ifndef BLOCK_IMPL
#define BLOCK_IMPL
struct__block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
// 省略部分代码
#endif
第一个成员isa指针用来表示该结构体的类型,使其仍然处于Cocoa的对象体系中,类似Python对象系统中的PyObject。
第二、三个成员是标志位和保留位。
第四个成员是对应的“匿名函数”,在这个例子中对应函数:
[cpp]
static void __main_block_func_0(struct__main_block_impl_0 *__cself) {
inti = __cself->i; // bound by copy
printf("%d\n", i);
}
函数__main_block_func_0引入了参数__cself,为struct __main_block_impl_0 *类型,从参数名称就可以看出它的功能类似于C++(www.cppentry.com)中的this指针或者Objective-C的self。
而struct __main_block_impl_0的结构如下:
[cpp]
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int i;
__main_block_impl_0(void*fp, struct__main_block_desc_0 *desc, int_i, intflags=0) : i(_i) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
从__main_block_impl_0这个名称可以看出该结构体是为main函数中第零个block服务的,即示例代码中的blk;也可以猜到不同场景下的block对应的结构体不同,但本质上第一个成员一定是struct __block_impl impl,因为这个成员是block实现的基石。
结构体__main_block_impl_0又引入了一个新的结构体,也是中间代码里最后一个结构体:
[cpp]
static struct __main_block_desc_0 {
unsigned long reserved;
unsigned long Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct__main_block_impl_0)};
可以看出,这个描述性质的结构体包含的价值信息就是struct __main_block_impl_0的大小。
最后剩下main函数对应的中间代码:
[cpp]
int main(intargc, constchar * argv[])
{
int i = 1024;
void(*blk)(void) = (void(*)(void))&__main_block_impl_0((void*)__main_block_func_0, &__main_block_desc_0_DATA, i);
((void(*)(struct__block_impl *))((struct__block_impl *)blk)->FuncPtr)((struct__block_impl *)blk);
return 0;
}
从main函数对应的中间代码可以看出执行block的本质就是以block结构体自身作为__cself参数,这里对应__main_block_impl_0,通过结构体成员FuncPtr函数指针调用对应的函数,这里对应__main_block_func_0。
其中,局部变量i是以值传递的方式拷贝一份,作为__main_block_impl_0的构造函数的参数,并以初始化列表的形式赋值给其成员变量i。所以,基于这样的实现,不允许直接修改外部变量是合理的——因为按值传递根本改不到外部变量。
4. 从实现上看如何修改外部变量(__block类型指示符)
如果想要修改外部变量,则需要用__block来修饰:
[cpp]
int main(intargc, constchar * argv[])
{
__block int i = 1024;
void(^blk)(void) = ^{ i = 0; printf("%d\n", i); };
blk();
return0;
}
此时再看中间代码,发现多了一个结构体:
[cpp]
struct __Block_byref_i_0 {
void *__isa;
__Block_byref_i_0 *__forwarding;
int __flags;
int __size;
int i;
};