美文网首页iOS面试iOS基础知识
Block变量捕获详解(一)

Block变量捕获详解(一)

作者: 鄂北 | 来源:发表于2021-08-26 17:35 被阅读0次
    • 什么是Block变量捕获
      block变量捕获就是在block内部创建一个变量来存放外部变量
    • 什么是值捕获
      block将外部变量的值存放到了内部新创建的一个变量中
    • 什么是指针捕获
      block将外部变量的指针存放到了内部新创建的一个变量中
    • 会对全局变量捕获吗
      不会对全局变量捕获,只会对局部变量进行捕获

    问题1

        int age = 10;
        void (^captureBlock)(void) = ^{
            NSLog(@"age is %d",age);
        };
        age = 20;
        captureBlock();
    

    问题:打印出来age是多少
    正确答案:10
    这是一道关于block的变量捕获的问题,如果对block变量捕获不是很明白的话,很容易说出age是20的错误答案。在block还没调用时,block已经对age的值捕获了,并在block内部生成了一个age变量,将外部age的值赋值了自己生成的age,这时block内部的age的值已经跟外部的没有关联了,所以当外部值改变时并不会影响到内部的值。这种情况称为block的值捕获。
    在1-1可以看到,在内部已经另外生成了一个age。


    1-1.png

    问题2

        int age = 10;
        static int height = 10;
        void (^captureBlock)(void) = ^{
            NSLog(@"age is %d,height is %d",age,height);
        };
        age = 20;
        height = 20;
        captureBlock();
    

    问题:打印的age和height分别是多少
    答案:age:10 height:20
    这个问题对比上个问题多了个height变量,但是这个变量跟age是有区别的,height是static变量。在运行时block对static局部变量的捕获是指针捕获,block中存放的是外部height变量的指针,当外部的值改变时内部值也会跟着改变。从2-1可以看出,在编译以后main函数block中age是值传递,height是指针传递。2-2中block内部也分别生成了int age和int *height用来接收外部的值。


    2-1.png
    2-2.png
    为什么局部变量age是值传递而static修饰的局部变量是指针传递呢?
    • 因为局部变量age在离开作用域时(就是离开大括号时)就会被释放,如果block是个全局,在其他作用域调用时,如果age是指针传递(保存的是指针),这时block去调用age时,age已经离开作用域被释放了,内存已经不存在了,这时就会报错,存在访问野指针的情况。所以对于局部变量非static修饰时,block就会值捕获。
    • static修饰的局部变量其内存会一直存在,不会因为离开作用域而被释放,所以当全局block在其他作用域调用时不会报错。
    //定义block类型
    void(^block)(void);
    
    void test(){
        int age = 10;
        static int height = 20;
    //在block内部访问 age , height
        block = ^{
            NSLog(@"age is %d, height is %d",age,height);
        };
        age = 20;
        height = 20;
    }
    
    //在main函数中调用
    int main(int argc, const char * argv[]) {
            test();
     //test调用后,age变量就会自动销毁,如果block内部是保留age变量的指针,那么我们在调用block()时,就出现访问野指针
            block();
    }
    

    问题3

    先声明两个全局变量age_和height_

    int age_;
    int height_;
    
        age_ = 10;
        height_ = 10;
        void (^captureBlock)(void) = ^{
            NSLog(@"age is %d,height is %d",age_,height_);
        };
        age_ = 20;
        height_ = 20;
        captureBlock();
    

    问题:打印的age和height分别是多少
    答案:age:20 height:20
    这个问题和前面两个问题又有所区别,这次age和height是一个全局变量,这次打印20的答案不是因为block的指针捕获导致的。从3-1中可以看到,在编译以后block中并没有生成一个age和height变量,所以block并没有对age和height两个变量进行捕获。因为age和height是全局变量,在任何的作用域下都是能调用的,所以block不会多此一举对其进行捕获,在内部直接访问就可以。


    3-1.png

    block变量捕获总结

    1. block只会对局部变量捕获不会对全局变量捕获
      因为局部变量只能在本作用域内才能被调用,block为了能在其他作用域内调用只能对其捕获。全局变量在任何地方都能被调用,所以不需要对其捕获。
    2. 对static局部变量是指针捕获,auto局部变量是值捕获
      在局部变量中不是static变量的默认为auto变量

    Block的三种类型(二)
    Block对象捕获(三)
    __block修饰符(四)
    Block循环引用(五)

    相关文章

      网友评论

        本文标题:Block变量捕获详解(一)

        本文链接:https://www.haomeiwen.com/subject/ytjuiltx.html