iOS - Block变量截获

简介: 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开发
iOS block修饰符用copy还是strong
iOS block修饰符用copy还是strong
149 0
|
iOS开发 Python
iOS小技能:lldb打印block参数签名
iOS逆向时经常会遇到参数为block类型,本文介绍一个lldb script,可快速打印出Objective-C方法中block参数的类型。
199 0
iOS小技能:lldb打印block参数签名
|
iOS开发 开发者
iOS开发 - 如何写出漂亮的block
iOS开发 - 如何写出漂亮的block
105 0
|
iOS开发
iOS开发- 关于Block的几种应用
iOS开发- 关于Block的几种应用
117 0
|
自然语言处理 iOS开发
IOS——Block
IOS——Block
79 0
|
iOS开发
iOS代理 通知 block传值的规范写法
iOS代理 通知 block传值的规范写法
146 0
|
存储 API iOS开发
iOS Principle:Block(下)
iOS Principle:Block(下)
131 0
iOS Principle:Block(下)
|
C语言 iOS开发 C++
iOS Principle:Block(上)
iOS Principle:Block(上)
115 0
iOS Principle:Block(上)
|
存储 C语言 iOS开发
iOS Principle:Block(中)
iOS Principle:Block(中)
121 0
|
iOS开发
iOS开发:block死循环及__weak弱引用提前释放的问题解决
block死循环及__weak弱引用提前释放的问题解决
323 0