__block能够修改变量的原因

为什么不加__block不能修改变量值

普通变量,数值型或对象型,没有加__block时,Block捕获的是变量,不是变量的地址,因为在函数里对变量做修改不起任何作用,所以编译器层面禁止对捕获的变量进行修改。如果捕获的是变量的地址的话,就可以修改,例如:

static int num = 10;

bbk blk = ^{
    num++;
};

NSLog(@"%d", num);
blk();
NSLog(@"%d", num);

输出结果:
10
11

编译成C++,看看对静态变量num做了什么:

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

可以看到Block捕获的是静态变量的地址"int *num",所以可以根据这个指针对静态变量做修改。

为什么加了__block就能修改变量值

使用了__block,可以修改变量值,根本原因还是因为获取到了变量的地址,看一下这段代码:

int main(int argc, const char * argv[])
{
    __block int a = 100;
    
    Blk blk_t;
    {
        blk_t = ^(id obj){
            a = 200;
        };
    }
    
    blk_t(@"Hello");
    
    return 0;
}

编译成C++看一下我们的“a=200”究竟做了什么,

static void __main_block_func_0(struct __main_block_impl_0 *__cself, id obj) {
  __Block_byref_a_0 *a = __cself->a; // bound by ref

            (a->__forwarding->a) = 200;
        }

__forwarding指针是一个指向自己__block实例的指针(当在栈上时),又通过__forwarding指针取到了变量a的地址进行赋值,所以最终是拿到了变量的地址,所以可以对变量进行修改。

你可能感兴趣的:(__block能够修改变量的原因)