iOS多线程编程和内存管理---block截获自动变量的解释(2)

前面已经介绍了block是带有局部变量(自动变量)的匿名函数,那么什么是带有局部变量呢?看看下面的的例子

int main(int argc, const char * argv[]) {

    int dmy = 256;
    int val = 10;
    const char *fmt = "val = %d\n";
    void(^blk) (void) = ^{printf(fmt ,val);};


    val = 2;
    fmt = "These values were changed. val = %d\n";

    blk();

    return 0;
}

输出结果:val = 10

Block中,block截获所使用的自动变量的值这里就是保存val=10的val的值,即保存val的瞬间值,正因为block保存了val的值,所以之后将val的值改变也不会影响block执行时val的值,所以输出10

下面我们利用clang -rewrite-objc main.m看看底层源代码

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;

//与上一篇比较,在block中使用的变量,在__main_block_impl_0结构体中出现
//Blocks的自动变量截获只会针对block使用的自动变量
//block中没有使用的变量不会被追加,dmy没有被追加
  const char *fmt;
  int val;

//__main_block_impl_0的构造函数中当然也会出现那两个变量
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, int flags=0) : fmt(_fmt), val(_val) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  const char *fmt = __cself->fmt; // bound by copy
  int val = __cself->val; // bound by copy
   printf(fmt ,val);
}

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

int main(int argc, const char * argv[]) {

    int dmy = 256;
    int val = 10;
    const char *fmt = "val = %d\n";
    void(*blk) (void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, fmt, val));

    val = 2;
    fmt = "These values were changed. val = %d\n";

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

    return 0;
}

分析
(1)由上面源代码中拿出__main_block_impl_0的构造函数,在初始化__main_block_impl_0时,根据传递的参数对由自动变量追加的成员变量进行初始化

  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, const char *_fmt, int _val, int flags=0) : fmt(_fmt), val(_val) 

使用执行block语法(即定义的时候)的自动变量fmt和val来初始化__main_block_impl_0结构体实例,初始化实例如下

    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = 0;
    impl.FuncPtr = __main_block_fun_0;
    Desc = &__main_block_desc_0_DATA;
    fmt = "val = %d\n";
    val = 10;

由此可知,在__main_block_impl_0的实例中,自动变量被截获。

(2)看看block语法转换的代码

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  const char *fmt = __cself->fmt; // bound by copy
  int val = __cself->val; // bound by copy
   printf(fmt ,val);
}

截获的 __main_block_impl_0结构体实例的成员变量上的自动变量实在Block之前被声明定义的,所以使用之前的val=10的值执行。

总的来说,"截获自动变量"意味着在执行Block语法时,Block语法表达式所使用的自动变量的值被保存到Block的结构体实例中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员的修养

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值