iOS:Block变量捕获

这篇博客我们从一个很常见的题目入手。

int age = 10;   
void (^myblock)(void) =  ^{
  NSLog(@"%d",age);
};
age  = 20;
myblock();

这个题目就涉及到了block内访问外部变量,block有个变量捕获机制,

我们新建一个mac的命令行工程,把上面代码写进去,然后用clang把main.m文件编译为cpp的文件看一下。

具体的block底层结构上一篇文章我们已经说过了,这里我们针对结构就不在赘述,直接说核心点。

auto类型局部变量

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int age;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

可以看到,在block的内部,多了一个age变量。而且从初始化的函数来看,这个__main_block_impl_0中age的值是外面传进来赋给他的。我们看一下main函数中。

 int age = 10;

void (*myblock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, age));

age = 20;

((void (*)(__block_impl *))((__block_impl *)myblock)->FuncPtr)((__block_impl *)myblock);

可以看出来在这个block初始化的过程中,就把age的值,也就是10,传了进去,赋值给了block内部的age变量。

那我再看一下打印的时候的age是什么情况。

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int age = __cself->age; // bound by copy
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_6l_80sfw0tn35bg4dxc51jlq_bw0000gn_T_main_3b5bf4_mi_0,age);
}

打印的这个age就是block自己内部的这个ege变量(值为10),所以我们在执行block之前,改变外面的age值为20,其实改变的不是内部要打印的这个age了,所以打印出来结果