OC底层-Block本质(二、变量捕获)
2020/6/29 23:27:20
本文主要是介绍OC底层-Block本质(二、变量捕获),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
为了保证block内部能够正常访问外部的变量,block有一个变量捕获机制。
局部变量
auto 变量(默认的auto)
在上一篇代码中我们已经了解过block对age变量的捕获。 auto自动变量,离开作用域就销毁,局部变量前面自动添加auto关键字。自动变量会捕获到block内部,也就是说block内部会专门新增加一个参数来存储变量的值。 auto只存在于局部变量中,访问方式为值传递,通过上述对age参数的解释我们也可以确定确实是值传递。
static变量
static 修饰的变量为指针传递,同样会被block捕获。
接下来分别添加auto修饰的局部变量和static修饰的局部变量,重看源码来看一下他们之间的差别:
auto int a = 10; static int b = 10; void(^block)(void) = ^{ NSLog(@"hello, a = %d, b = %d", a,b); ///打印 hello, a = 10, b = 20 }; a = 20; b = 20; block(); 复制代码
通过命令行我们查看源代码:
从上述源码中可以看出,a,b两个变量都有捕获到block内部。但是a传入的是值,而b传入的则是地址。
为什么两种变量会有这种差异呢,因为自动变量可能会销毁,block在执行的时候有可能自动变量已经被销毁了,那么此时如果再去访问被销毁的地址肯定会发生坏内存访问,因此对于自动变量一定是值传递而不可能是指针传递了。而静态变量不会被销毁,所以完全可以传递地址。而因为传递的是值得地址,所以在block调用之前修改地址中保存的值,block中的地址是不会变得。所以值会随之改变。
全局变量
我们以同样的方式来研究下block是否捕获全局变量
int a = 10; static int b = 10; int main(int argc, const char * argv[]) { @autoreleasepool { void(^block)(void) = ^{ NSLog(@"hello, a = %d, b = %d", a,b); /// 打印hello, a = 20, b = 20 }; a = 20; b = 20; block(); } return 0; } 复制代码
源代码:
通过上述代码可以发现,__main_block_imp_0并没有添加任何变量,因此block不需要捕获全局变量,因为全局变量无论在哪里都可以访问。 局部变量因为跨函数访问所以需要捕获,全局变量在哪里都可以访问 ,所以不用捕获。 所以用下面这张图做个总结:
总结:局部变量都会被block捕获,自动变量是值捕获,静态变量为地址捕获。全局变量则不会被block捕获
疑问思考:以下代码中block是否会捕获变量呢?
#import "Person.h" @implementation Person - (void)test { void(^block)(void) = ^{ NSLog(@"%@",self); }; block(); } - (instancetype)initWithName:(NSString *)name { if (self = [super init]) { self.name = name; } return self; } @end 复制代码
这篇关于OC底层-Block本质(二、变量捕获)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-10-05Swift语法学习--基于协议进行网络请求
- 2022-08-17Apple开发_Swift语言地标注释
- 2022-07-24Swift 初见
- 2022-05-22SwiftUI App 支持多语种 All In One
- 2022-05-10SwiftUI 组件参数简写 All In One
- 2022-04-14SwiftUI 学习笔记
- 2022-02-23Swift 文件夹和文件操作
- 2022-02-17Swift中使用KVO
- 2022-02-08Swift 汇编 String array
- 2022-01-30SwiftUI3.0页面反向传值