美文网首页
iOS - Block变量截获

iOS - Block变量截获

作者: 码代码的小马 | 来源:发表于2021-05-02 15:32 被阅读0次

    Block技术合集
    Block的写法及使用
    iOS - __block 修饰符底层探索

    先看代码

    static int number1 = 10; //全局静态变量
    
    // Block捕获变量
    - (void)captureVariableBlock {
        
        static int number2 = 10;     //局部静态变量
        int number3 = 10;            //局部变量
        __block int number4 = 10;    //__block修饰的局部变量
        NSMutableArray *array = [NSMutableArray arrayWithObjects:@"obj1",@"obj2", nil];
        void(^captureBlock)(void) = ^ {
            NSLog(@"capture Variable \n number1 = %d, \n number2 = %d, \n number3 = %d, \n number4 = %d, \n array = %@", number1, number2, number3, number4, array);
            [array addObject:@"obj4"];
        };
        number1 = 2;
        number2 = 2;
        number3 = 2;
        number4 = 2;
        [array addObject:@"obj3"];
        array = nil;
        captureBlock();
    }
    }
    

    打印结果:

    2021-05-01 17:39:26.836630+0800 BlockDemo[14620:6891187] capture Variable 
     number1 = 2, 
     number2 = 2, 
     number3 = 10, 
     number4 = 2, 
     array = (
        obj1,
        obj2,
        obj3
    )
    

    通过终端命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m -o ViewController.cpp获取编译后的.cpp文件,经整理简化后如下:

    struct __ViewController__captureVariableBlock_block_impl_0 {
      struct __block_impl impl;
      struct __ViewController__captureVariableBlock_block_desc_0* Desc;
      int *number2;
      int number3;
      NSMutableArray *array;
      __Block_byref_number4_2 *number4; // by ref
      __ViewController__captureVariableBlock_block_impl_0(void *fp, struct __ViewController__captureVariableBlock_block_desc_0 *desc, int *_number2, int _number3, NSMutableArray *_array, __Block_byref_number4_2 *_number4, int flags=0) : number2(_number2), number3(_number3), array(_array), number4(_number4->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    

    查看__ViewController__captureVariableBlock_block_impl_0结构体中,int *_number2, int _number3, NSMutableArray *_array, __Block_byref_number4_2 *_number4,,
    注意:impl.isa = &_NSConcreteStackBlock 说明该block是栈block
    可见,对于

    • oc对象 NSMutableArray *_array,捕获指针
    • 局部静态变量int *_number2捕获指针
    • 局部变量 int _number3捕获值
    • 全局变量并未捕获
    • __block修饰的变量也是以指针形式捕获的,并且生成了一个新的结构体
    struct __Block_byref_number4_2 {
      void *__isa;
    __Block_byref_number4_2 *__forwarding;
     int __flags;
     int __size;
     int number4;
    };
    

    该结构体有个熟悉int number4,即我们用__block修饰的变量
    这里__forwarding是指向自身的(栈Block)
    一般情况下,如果我们要对block捕获的局部变量进行赋值操作需要添加__block修饰符,而对全局变量,静态变量是不需要添加__block修饰符的(全局变量不需捕获,静态变量会捕获指针)
    另外,block里访问self或self成员变量都会去截获self

    可以看出,局部变量的值是block定义时的值,而不是block执行时的值

    block在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在block内部使用该只读拷贝。换句话说,block截获自动变量的初始值,或者block捕获的是自动变量的副本
    由于blick捕获了自动变量的瞬时值,所以在执行block语法后,即使改写block使用的自动变量的值也不会影响block执行时自动变量的值,所以上面局部变量的值打印是10

    捕获特性

    全局变量静态全局变量不捕获,直接取值

    局部变量基本数据类型时,捕获值
    局部变量oc对象时,连同所有权修饰符一起捕获
    局部静态变量,捕获其指针(上述numer2打印为10)

    相关文章

      网友评论

          本文标题:iOS - Block变量截获

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