iOS block以及变量捕获

news/2025/3/8 0:42:08/

Block是什么

Block也是一个OC对象,内部也有isa指针。

扩展:

instance对象的isa指向class对象
class对象的isa指向meta-class对象
meta-class对象的isa指向基类的meta-class对象

void (^block)(void) = ^{NSLog(@"Hello");};NSLog(@"%@", [block class]);NSLog(@"%@", [[block class] superclass]);NSLog(@"%@", [[[block class] superclass] superclass]);NSLog(@"%@", [[[[block class] superclass] superclass] superclass]);
2020-11-09 22:24:30.042560+0800 Interview01-Block的本质[1489:30598] __NSGlobalBlock__
2020-11-09 22:24:30.043005+0800 Interview01-Block的本质[1489:30598] __NSGlobalBlock
2020-11-09 22:24:30.043103+0800 Interview01-Block的本质[1489:30598] NSBlock
2020-11-09 22:24:30.043163+0800 Interview01-Block的本质[1489:30598] NSObject

Block的类型

__NSGlobalBlock__(_NSConcreteGlobalBlock)(存放在数据区) (不访问auto变量的block 即便是访问了static局部变量 或者全局变量)

__NSStackBlock__(_NSConcreteStackBlock)(存放在栈区 系统管理内存)(访问了auto变量:auto变量就是局部变量)

__NSMallocBlock__(_NSConcreteMallocBlock) (存放在堆区 程序员管理内存) (__NSStackBlock__调用了copy)
 

不同类型变量的捕获方式

1、局部变量和block

使用局部变量的block

int main(int argc, const char * argv[]) {@autoreleasepool {int age = 10;block = ^{// age的值捕获进来(capture)NSLog(@"age is %d, ", age);};age = 20;block();}return 0;              
}

clang编译后的底层代码

struct __test_block_impl_0 {struct __block_impl impl;struct __test_block_desc_0* Desc;int age;__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int flags=0) : age(_age) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};

可以看到,在block的内部多了成员变量_age,并且在构造这个block时,会把age的值直接传进去,几_age=age,可以看出来这时是block捕获了局部变量,并且进行了值传递。

2、静态局部变量

int main(int argc, const char * argv[]) {@autoreleasepool {// auto:自动变量,离开作用域就销毁auto int age = 10;static int height = 10;void (^block)(void) = ^{// age的值捕获进来(capture)NSLog(@"age is %d, height is %d", age, height); // 10  20};age = 20;height = 20;block();}return 0;
}

编译后的结果:

struct __test_block_impl_0 {struct __block_impl impl;struct __test_block_desc_0* Desc;int age;int *height;__test_block_impl_0(void *fp, struct __test_block_desc_0 *desc, int _age, int *_height, int flags=0) : age(_age), height(_height) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};//定义的时候
block = ((void (*)())&__test_block_impl_0((void *)__test_block_func_0, &__test_block_desc_0_DATA, age, &height));
//执行的时候
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {int age = __cself->age; // bound by copyint *height = __cself->height; // bound by copyNSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_d2875b_mi_0, age, (*height));}

可以看出来age传递的是值,但是静态局部变量height传递的是指针。

3、全局变量和block

int age_ = 10;
static int height_ = 10;
void (^block)(void);
int main(int argc, const char * argv[]) {@autoreleasepool {void (^block)(void) = ^{NSLog(@"age is %d, height is %d", age_, height_);};age_ = 20;height_ = 20;block();}return 0;
}

编译后:

struct __main_block_impl_0 {struct __block_impl impl;struct __main_block_desc_0* Desc;// 构造函数(类似于OC的init方法),返回结构体对象__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {impl.isa = &_NSConcreteStackBlock;impl.Flags = flags;impl.FuncPtr = fp;Desc = desc;}
};
//调用函数的时候
static void __test_block_func_0(struct __test_block_impl_0 *__cself) {NSLog((NSString *)&__NSConstantStringImpl__var_folders_2r__m13fp2x2n9dvlr8d68yry500000gn_T_main_d2875b_mi_0, age_, height_);}

可以看到全局变量没有捕获到block内部,是直接访问的,所以每次访问都能获得最新值。

未完待续

参考文档:

block ios 深入理解 ios __block的作用_imking的技术博客_51CTO博客
iOS OC基础知识笔记_ios oc y-CSDN博客

文章来源:https://blog.csdn.net/weixin_45157020/article/details/135573185
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ppmy.cn/news/1324702.html

相关文章

PHP反序列化总结4--原生类总结

原生类的简要介绍以及原生类和反序列化的关系 PHP 原生类指的是 PHP 内置的类,它们可以直接在 PHP 代码中使用且无需安装或导入任何库,相当于代码中的内置方法例如echo ,print等等可以直接调用,但是原生类就是可以就直接php中直接…

vue基于spring boot框架的发艺美发店理发店管理系统的设计q9xpe

店铺信息、美发信息是发艺美发店管理系统的重要组成部分,信息清晰、详细、准确,能够有效地促进发艺美发店管理系统的运行[5]。基础设定函数是对整个系统的总体布局进行合理安排,包括:店铺活动、物品信息、领用信息等。通过对各类资…

【Git】常用的Git操作集合

常用的Git操作集合 1. 分支操作1.1 查看本地所有分支git branch 1.2 查看所有分支(包含本地远程仓库)git branch -a 1.3 切换分支git checkout test 2. 常用基本操作2.1 查看 git 各存储区内(文件)状态git status 2.2 查看工作区与暂存区文件差异git dif…

【Python数据可视化】matplotlib之设置子图:绘制子图、子图共享x轴坐标、调整子图间距、设置图片大小

文章传送门 Python 数据可视化matplotlib之绘制常用图形:折线图、柱状图(条形图)、饼图和直方图matplotlib之设置坐标:添加坐标轴名字、设置坐标范围、设置主次刻度、坐标轴文字旋转并标出坐标值matplotlib之增加图形内容&#x…

【SpringBoot】SpringBoot 项目初始化方法

github 搜索 springboot 模板 github 搜索 springboot 模板,拉取现成代码。 SpringBoot 官方的模板生成器 SpringBoot 官方的模板生成器(https://start.spring.io/) 在 IDEA 开发工具中生成 这里我修改成阿里的镜像主要是要使用 Java8。 …

2.【Linux】(进程的状态||深入理解fork||底层剖析||task_struct||进程优先级||并行和并发||详解环境变量)

一.进程 1.进程调度 Linux把所有进程通过双向链表的方式连接起来组成任务队列,操作系统和cpu通过选择一个task_struct执行其代码来调度进程。 2.进程的状态 1.运行态:pcb结构体在运行或在运行队列中排队。 2.阻塞态:等待非cpu资源就绪&am…

华为手表开发:WATCH 3 Pro(10)获取心率_java 华为手表获取心跳

华为手表开发:WATCH 3 Pro(10)获取心率_java 华为手表获取心跳 Excerpt 文章浏览阅读1.2k次。鸿蒙开发,获取手表心跳,按钮点击后触发的方法,我们将跳转页面的代码写在这个位置就可以实现点击按钮进行跳转页面的动作。在HTML文件“index.hml”,添加按钮,这里按钮用到是标…

02-k8s学习笔记之相关组件

1、控制面板组件(Master) kube-apiserver API 服务器是 Kubernetes 控制平面的组件, 该组件负责公开了 Kubernetes API, 负责处理接受请求的工作。 API 服务器是 Kubernetes 控制平面的前端。kube-controller-manager kube-con…