关于block的本质,你懂了吗?

简介: block应用的目的: 把将来想要执行的代码封装起来,然后在恰当的时刻再执行代码。block本质:1、block是封装了函数调用和函数调用环境(如:block内部要使用的参数)的OC对象。2、block本质上也是一个OC对象,它内部也有一个isa指针(只要内部有一个isa指针,我们就可以认为他是OC对象,因为NSObject作为最基础的OC对象,第一个成员变量就是isa指针,这是OC对象的特征)。

本节带你分析 block 的底层实现(block本质)。

开始具体内容之前先把结果直接跑出来,以便更好的理解:


block应用的目的: 把将来想要执行的代码封装起来,然后在恰当的时刻再执行代码。

block本质:

1、block是封装了函数调用和函数调用环境(如:block内部要使用的参数)的OC对象。

2、block本质上也是一个OC对象,它内部也有一个isa指针(只要内部有一个isa指针,我们就可以认为他是OC对象,因为NSObject作为最基础的OC对象,第一个成员变量就是isa指针,这是OC对象的特征)。


再来一张下饭的底层结构图:


de9ab1f1ffb140f3b1d6d0604c94b92f.png

上面看不懂的没关系,下面举个例子,一步步带你去剖析,block里面到底做什么:


1、实现一个简单的block


下面我们来一步步分析block的实现原理,以下面一段代码为例,来查看OC的底层实现:


int main(int argc, const char * argv[]) {
    @autoreleasepool {
      // 局部变量赋值
      int age = 10;
      // 定义 block 变量
        void(^block)(void) = ^{
          // block内部应用外部的局部变量
           NSLog(@"Hello, World--age:%d",age);
        };
        // block执行
        block();
    }
    return 0;
}


2、代码转成C++


打开命令行,cd 到 main.m 的目录下,执行以下命令:

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m

执行玩命令后,在同目录下会生成 main.cpp 文件,然后将文件导入项目(注意:该文件不参与编译)。


3、底层代码分析


内部每一行代码都配置了详细的说明:



// 1、程序入口
int main(int argc, const char * argv[]) {
  int age = 10;
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        /**
         * 2、定义block变量(已经移除强制转化的前缀,提高代码可读性)
         * 这句代码的含义是:调用 __main_block_impl_0() 结构体的构造函数,创建出一个结构体对象,并且把这个结构体对象地址赋值给 *block 变量
         * 
         * --------------------------------
         * 3、函数 __main_block_impl_0 参数说明
         * @param __main_block_func_0: 3.1、block的执行函数,传递给结构体的 FuncPtr 变量
         * @param &__main_block_desc_0_DATA: 3.2、关于block描述的结构体
         * @param age: 3.3、外部传入的局部变量
         * @return &结构体
         *  
         *  ----------------------------------
         *  4、以上分析可知该函数调用返回的是一个结构体地址:
         * 类似:void(*block)(void) = &结构体
        */
        void(*block)(void) = &__main_block_impl_0(
          __main_block_func_0,
        &__main_block_desc_0_DATA, 
        age
        );
        // 执行block内部代码
        block->FuncPtr(block);
    }
    return 0;
}
// 2.1、调用该函数,返回的是一个结构体对象
struct __main_block_impl_0 {
  struct __block_impl impl;// 2.1a、block结构体:主要参数信息
  struct __main_block_desc_0* Desc;// 2.1b、block结构体:关于block信息的描述(记录内存大小)
  int age;// 2.1c、封装了block的访问变量
   // 2.1d、cpp的构造函数(类似OC的init方法,原来什么类型,返回什么对象类型)赋值:返回结构体对象
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age, int flags=0) : age(_age) {
    // 给变量赋值
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
// 2.1a、block结构体:主要参数信息
struct __block_impl {
  void *isa;// 因为结构体中有 isa 指针,那么可以知道 block 是一个OC对象
  int Flags;//标记,默认为0
  int Reserved;// 预留参数
  void *FuncPtr;// 指向将来要执行的函数地址指针
};
// 2.1b、block结构体:关于block信息的描述(记录内存大小)
static struct __main_block_desc_0 {
  size_t reserved;// 预留参数
  size_t Block_size;// 记录block占据的内存大小
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
// 3.1、封装了 block 执行逻辑的函数
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int age = __cself->age; // bound by copy
  NSLog((NSString *)&__NSConstantStringImpl__var_folders_vc_pn677_yj1sz8hgf_q5bjvssc0000gn_T_main_9a9627_mi_0,age);
}
// 3.2、关于block描述结构体的肤质
static struct __main_block_desc_0 {
  size_t reserved;// 预留参数 0
  size_t Block_size;// 计算block大小后的值
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};


提问:block的原理是怎样的?(本质是什么?)


block是封装了函数调用以及调用环境的OC对象。


相关文章
系列文章深度解读|SwiftUI 背后那些事儿
前言 今年苹果的WWDC你看了吗?苹果在2019年的WWDC的重头戏当然非SwiftUI莫属:全新的声明式语法、绑定式API、和响应式变成框架Combine。这一切的一切都预示着即将在Apple Native布局系统掀起一场革命。
18029 0
|
SQL 缓存 网络协议
C++实现MySQL数据库连接池
为了提升MySQL数据库(基于C/S设计(客户端-服务器))的访问瓶颈,除了在服务器端增加缓冲服务器缓存常用的数据之外
751 0
|
存储 算法 Java
【算法】Java实现AES算法
AES(Advanced Encryption Standard)是一种对称密钥加密算法,它是目前最常用和广泛接受的加密算法之一。AES在2001年由美国国家标准技术研究所(NIST)选定为替代DES的标准加密算法。
606 0
|
缓存 大数据 数据处理
Velocity循环详解
Velocity循环详解
|
监控 Linux 数据处理
深入了解Linux的logger命令:日志记录与监控
`logger`命令在Linux中用于向系统日志发送消息,便于记录系统事件和应用程序状态。它与`syslogd`配合,允许用户指定优先级、标识符和内容。简单易用,灵活适应不同日志需求。示例:`logger -p user.warning -t MYAPP "A warning occurred."`。注意选择合适优先级,使用有意义的标识符,并结合其他工具如`logrotate`进行日志管理。
|
消息中间件 SQL NoSQL
再记一次止于三面的阿里面试之旅
Hello 大家好,我是阿粉,最近心情不是很好,因为阿粉面试阿里三面挂掉了, 当收到下面这封邮件的时候阿粉内心是拔凉拔凉的。阿粉被 “Unfortunately”,“another candidate” 这几个词深深的伤害到了。不过伤心归伤心,该自我总结还是得自我总结的,有机会再战。
|
存储 SQL JSON
大分区表高并发性能提升100倍?阿里云 RDS PostgreSQL 12 特性解读
世界上几乎最强大的开源数据库系统 PostgreSQL,于 2019 年 10 月 3 日发布了 12 版本,该版本已经在阿里云正式发布。PostgreSQL 12 在功能和性能上都有很大提升,如大分区表高并发性能提升百倍,B-tree 索引空间和性能优化,实现 SQL 2016 标准的 JSON 特性,支持多列 MCV(Most-Common-Value)统计,内联 CTE(Common table expressions)以及可插拔的表存储访问接口等。本文对部分特性进行解读。
3575 0
大分区表高并发性能提升100倍?阿里云 RDS PostgreSQL 12 特性解读
|
域名解析 安全 CDN
隐藏服务器真实IP的几种方法
隐藏服务器真实IP的几种方法
|
XML JavaScript 前端开发
使用 doscify 将文章写成文档一般丝滑
使用 doscify 将文章写成文档一般丝滑
273 0
|
Android开发
泼辣修图2023最新版功能介绍及使用教程
看了看后台管理,发现修图软件比较受大家欢迎,所以今天我打算在更新一个修图软件泼辣修图!泼辣修图是一款深受用户喜爱的修图软件,所以今天为大家推荐这款修图APP,经过汉化,所有滤镜和工具都能免费用,无任何的廣搞! 无论你是入门新手还是摄影专家,泼辣修图都可以满足你的一切需求。对于入门新手而言,泼辣修图搭载的先进自动增强工具和富有创意的图像滤镜,可以帮助他们快速雕琢图像的每一个细节。对于摄影专家而言,图层混合、局部调整、曲线工具等等功能则是他们青睐有加的专业特性。
924 0
下一篇
oss云网关配置