• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

block的本质,你懂了吗

武飞扬头像
瓜子三百克
帮助1

学新通

✅作者简介:大家好我是瓜子三百克,一个非科班出身的技术程序员,还是喜欢在学习和开发中记录笔记的博主小白!
📃个人主页:瓜子三百克的主页
💖如果觉得博主的文章还不错的话,请点赞👍 收藏⭐️ 留言📝支持一下博主哦🤞


本节带你分析 block 的底层实现(block本质)。
开始具体内容之前先把结果直接跑出来,以便更好的理解:

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

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

上面看不懂的没关系,下面举个例子,一步步带你去剖析,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对象。



**🏆结束语🏆 **

最后如果觉得我写的文章对您有帮助的话,欢迎点赞✌,收藏✌,加关注✌哦,谢谢谢谢!!

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfhjgib
系列文章
更多 icon
同类精品
更多 icon
继续加载