Block(二)

Block内访问局部变量

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        //局部变量num
        int num=100;
        ^{
            //进行访问,输出结果为100
            NSLog(@"%d",num);
        }();
        
    }
    return 0;
}

通过输出结果可以很明显看出来,block内部是可以对局部变量进行访问的,我们来看另一种情况

int num=100;
void(^pNum)(void)=^{
      NSLog(@"%d",num);
    };
//对num进行修改
num=101;
pNum();

简单对上面的代码一看,分析一下结果,发现输出的为100

这是因为在声明block之后,调用block时里面的局部变量为声明block之前的局部变量的值,也就是未修改的旧值。

那么我们能不能在block内部对局部变量进行修改呢?

        int num=100;
        void(^pNum)(void)=^{
            num++;            //这一句会报错
            NSLog(@"%d",num);
        };
        pNum();

所以在block内部是不能对局部变量进行修改的。

我们分析一下原理:

  1. 在Block定义时便是将局部变量的值传给Block变量所指向的结构体,也就是copy了一个num的值给了block变量所在的结构体,block变量所在结构体中的global和外面的num并不是同一个,只是值是一样。(即为浅拷贝)
  2. 外部的num是一个变量,但是block变量所指向的结构体中的num是一个常量,所以不能进行 ++操作。
  3. 因此在调用Block之前对局部变量进行修改并不会影响Block内部的值,因为这两个值分别存储在各自的内存中,同时内部的值也是不可修改的,因为它是一个常量。

那么我们如果要在block中对局部变量进行修改的话,我们需要对局部变量用__block修饰。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        __block int num=100;
        void(^pNum)(void)=^{
            num++;
            NSLog(@"%d",num);
        };
        pNum();
        
    }
    return 0;
}

 如上述代码,输出的结果则为101。

与此同时,在这种情况下,如果在声明block后,调用block前,进行局部变量的修改,block中的局部变量不再为旧值,而为修改后的新值。

        __block int num=100;
        void(^pNum)(void)=^{
            num++;
            NSLog(@"%d",num);
        };
        num++;
        pNum();

如上,输出的结果为102。 

我们再分析一下__block修饰的局部变量能修改的原理:

  1. 在局部变量前使用__block修饰,在Block定义时便是将局部变量的指针传给Block变量所指向的结构体,因此在调用Block之前对局部变量进行修改会影响Block内部的值,同时内部的值也是可以修改的。(即为深拷贝)
  2. 这时在block中访问num是通过指针访问,通过指针指向的内存地址取出num值,同时通过这个指针也可以修改内存中的存储内容。

 

 总结一下

  1. block中可以访问局部变量,但是不能修改。原因局部变量传入block时,是将局部变量的值copy到block所在的结构体中。即为浅拷贝,拷贝完后为常量。
  2. block中可以访问和修改__block修饰的局部变量。原因为此时是深拷贝,是将局部变量的地址传入到block所在的结构体中,可以通过访问这个地址,修改局部变量的值和获得该局部变量最新的值。

有关深浅拷贝的更多内容,在我的OC的修饰符中有详细的描写。

Block内访问全局变量

情况很简单,看下代码和输出结果。

int num=100;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        void(^pNum)(void)=^{
            num++;
            NSLog(@"%d",num);
        };
        num++;
        pNum();
        
    }
    return 0;
}

我们可以在block内部,对全局变量进行访问和修改,同样在block声明后、调用前修改变量的值,调用后的全局变量的值为修改后的新值。所以上述代码的结果也就为102。

原因很简单:就是因为全局变量是存在全局区的,block直接进行访问就行,无需copy传入到block中。

全局静态变量的情况也如上。

Block内访问静态变量

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        static int num=100;
        
        void(^pNum)(void)=^{
            num++;
            NSLog(@"%d",num);
        };
        num++;
        pNum();
        
    }
    return 0;
}

 这个时候的原理,和访问__block修饰的局部变量是一样的原理,自然情况也就是一样的,不多阐述。

为了更好的理解,放一张图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值