使用clang 的编译选项查看blocks
“clang -rewrite-objc 源代码文件名”
源代码:
int main ()
{
void (^blk)(void) = ^{ printf(“Block”); };
blk ();
return 0;
}
转换为:
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("Block");
}
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)
};
int main()
{
void (*blk)(void) = (void (*)(void)) & __main_block_impl_0( (void *)__main_block_func_0, &__main_block_desc_0_DATA);
((void (*)(struct __block_impl *))( (struct __block_impl *)blk)-> FuncPtr)((struct __block_impl *)blk);
return 0;
}
以上代码解析:
void (*blk)(void) = (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_0_DATA);
struct __main_block_impl_0 *blk = &tmp;
而 ((void (*)(struct __block_impl *))( (struct __block_impl *)blk)-> FuncPtr)((struct __block_impl *)blk);
则可以简化为:
(*blk—>impl.FuncPtr)(blk);
实际上就是 函数指针调用 函数。
typedef strcut objc_object {
Class isa;
} *id;
typedef strict objc_class *Class;
struct objc_class {
Class isa;
};
各类的结构体就是基于objc_class 结构体的class_t 结构体。
struct class_t {
struct class_t *isa;
struct class_t *superclass;
Cache cache;
IMP *vtable;
uintptr_t data_NEVER_USE;
};
总的来说,所谓“截获自动变量值”意味着在执行Block语法时,Block语法表达式所使用的自动变量值被保存到Block的结构体实例(Block自身)中。
当我们视图改变Block中的自动变量值时会出现编译错误。
解决的方法有两种:
①使用静态变量。Block 会保存静态变量的的指针对其进行访问。 将静态变量的指针传递给__main_block_impl_0 结构体的构造函数并保存。 但是我们并没有保存自动变量的指针。这是因为超出自动变量的作用域的时候,自动变量被废弃,通过指针来访问会产生不可预料的错误。但静态变量则不会。
②使用__block 存储域类说明符。
C语言有以下存储域类说明符: typedef , extern, static, auto, register.