如何在block内部修改外部变量?

int age = 10;
void (^block)(void) = ^{
    age = 20;
};
block();

如上代码,编译会报错,因为age变量会被捕获,因为是auto变量,所以是值传递..如果想修改age变量,办法如下:

__block转成C++后查看源码

struct __Block_byref_age_0 {
  void *__isa;
__Block_byref_age_0 *__forwarding;
 int __flags;
 int __size;
 int age;// 10
};

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  __Block_byref_age_0 *age; // by ref
  
  // 构造函数
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_age_0 *_age, int flags=0) : age(_age->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

凡是有isa都认为是Objective-C对象 可以看到生成的block内部多了一个成员变量,在构造函数里面使用了_age->__forwarding初始化这个变量,这个变量就是一个__Block_byref_age_0结构体,而这个结构体内部有age成员变量,这个__forwarding指向的就是这个__Block_byref_age_0结构体它自己;

查看age这个auto变量的修改源码

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_age_0 *age = __cself->age; // bound by ref

    (age->__forwarding->age) = 20;
}

编译器会将__block变量包装成一个对象

__block可以用于解决block内部无法修改auto变量值的问题

__block不能修饰全局变量、静态变量(static)