iOS不使用__block修改Block中的局部变量<指针篇>

FromBaidu.jpg

Laziness is like a lock, which bolts you out of the storehouse of information and makes you an intellectual starveling. –Bernard Shaw
懒惰就象一把枷锁,锁住了知识的仓库,使你的智力便得匮乏。–萧伯纳

示例1:

    int a = 10;
    NSLog(@"1---%p",&a);
    NSLog(@"1---%d",a);
    [UIView animateWithDuration:1 animations:^{
        NSLog(@"2--->:%p",&a);
        NSLog(@"2--->:%d",a);
    }];
    NSLog(@"3--->%p",&a);
    NSLog(@"3--->%d",a);
  • 结果:
    示例1.png

示例2:

    __block int a = 10;
    NSLog(@"1---%p",&a);
    NSLog(@"1---%d",a);
    [UIView animateWithDuration:1 animations:^{
        NSLog(@"2--->:%p",&a);
        NSLog(@"2--->:%d",a);
    }];
    NSLog(@"3--->%p",&a);
    NSLog(@"3--->%d",a);
  • 结果:

    示例2.png

  • 结论:

    对比示例1示例2发现不加__blockblock内部会重新生成了一变量。示例1中生成的变量依然在栈区,地址减4,不加__block之所以不能修改局部变量是因为编译器加了限制,默认不允许修改。而以上说明,并没有脱离变量a的作用域,详见执行顺序。因为[UIView animateWithDuration:中的block会立即执行,这也是为何不用weakSelf不会造成循环引用的原因。下面我们使用GCD,演示超过作用域的情况。


示例3:
    int a = 10;
    NSLog(@"1---%p",&a);
    NSLog(@"1---%d",a);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"2--->:%p",&a);
        NSLog(@"2--->:%d",a);
    });
    NSLog(@"3--->%p",&a);
    NSLog(@"3--->%d",a);
  • 结果:
    示例3.png

示例4:

    __block int a = 10;
    NSLog(@"1---%p",&a);
    NSLog(@"1---%d",a);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"2--->:%p",&a);
        NSLog(@"2--->:%d",a);
    });
    NSLog(@"3--->%p",&a);
    NSLog(@"3--->%d",a);
  • 结果:
    示例4.png
  • 结论:

    对比示例3示例4发现超过作用域生成的变量在堆区。有趣的是在示例4中:对比结果13打印的地址,尽管GCD没有执行,而a的地址已经发生了改变,也就是说在编译时a的地址已经发生了改变。接下来,我们将直接访问地址,来修改block中访问的“局部变量”,而不需要加__block.


示例5:
    int a = 10;
    NSLog(@"1---%p",&a);
    NSLog(@"1---%d",a);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        int *b = (int *)&a;
        *b = 20;
        NSLog(@"2--->:%p",&a);
        NSLog(@"2--->:%d",a);
    });
    NSLog(@"3---%p",&a);
    NSLog(@"3---%d",a);
  • 结果:
    示例5.png
  • 结论
    不加__block,在block中间接修改所谓的“局部变量”,实际上也是重新生成的局部变量,只是名字相同而已,超过作用域的变量a已经释放了,而使用指针只不过是绕开编译器的检查,间接通过地址修改内容。同理加上__block只是告诉编译器可以修改重新生成的变量。

我的上一篇文章:炫酷悬停交互视图

最后:

由于本人目前知识储备有限,以上说明中,也许会存在一些错误的描述和认识,还希望发现后你能及时指出,以免误导其他读者,在此谢过。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值