iOS block以及变量捕获

news/2024/7/20 20:08:17 标签: ios

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 copy
  int *height = __cself->height; // bound by copy


        NSLog((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博客


http://www.niftyadmin.cn/n/5330004.html

相关文章

Python 自学(八) 之模块

目录 1. import语句导入模块 P206 2. from ... import 语句导入模块 P207 3. 模块的搜索目录 sys.path P209 4. 以主程序的形式执行 __name__ P212 5. python中的包 P213 1. import语句导入模块 P206 同一目录下&…

MongoDB-数据库文档操作(1)

任务描述 文档数据在 MongoDB 中的插入和更新。 相关知识 本文将向大家介绍文档数据在 MongoDB 中的基本操作。 文档的数据结构和 JSON 基本一样,所有存储在集合中的数据都是 BSON 格式。BSON 是一种类 JSON 的一种二进制形式的存储格式,简称&#x…

字节发布Coze GPTs,可免费体验GPT-4与DALL3绘画模型

open AI发布ChatGPT以来,很多基于ChatGPT好玩的应用也随之而来。而OpenAI也发布了自己的GPT store。他允许任何人基于ChatGPT开发自己的应用并上传到GPT store里面。而字节基于发布的coze,可以让没有API的小伙伴免费使用GPT-4以及DELL-3等模型。 首先需要我们登陆到coze的官网…

NLP论文阅读记录 - 2022 | WOS 用于摘要法律文本的有效深度学习方法

文章目录 前言0、论文摘要一、Introduction1.1目标问题 二.相关工作三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结 前言 Effective deep learning approaches for summarization of legal texts(22&#x…

功能权限篇

文章目录 1. 如何设计一套权限系统1.1 目标1.2 权限模型1.2.1 模型一RBAC1.2.2 模型二ABAC 2.如何实现菜单的创建?2.1 表结构2.2 前端实现2.3 后端实现 3. 如何实现角色的创建?4.如何给用户分配权限 —— 将菜单赋予角色?5.如何给用户分配权限…

Linux 脚本编程题库

1.在主目录下新建一个test.sh文件,脚本功能为查找某文件是否存在(某文件名以参数形式传递),如果文件存在,则修改文件权限为用户主可读写,其他用户无任何权限,否则返回文件不存在! #…

专业课148,总分410+电子科技大学858信号与系统考研经验电子信息与通信

今年专业课148分,总分410顺利被电子科技大学录取,回望这一年复习还有很多不足,总结一下自己的复习经历,希望对大家复习有所帮助。 数学:(多动手,多计算,多总结,打好基础…

Github 2024-01-10 C开源项目日报Top10

根据Github Trendings的统计,今日(2024-01-10统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10C项目2PLpgSQL项目1Assembly项目1 LLaMA模型的C/C移植 创建周期:306 天开发语言&#xf…