Block笔记(2)—— 底层结构

作者: RUNNING_NIUER | 来源:发表于2019-08-07 14:20 被阅读16次

上一篇,我们初步认识了Block的一些基本知识。现在,我们来一起挖掘一下Block的底层结构。

首先还是新建一个命令行项目
定义一个最最简单的block
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        //Block的定义
        void (^block)(void) = ^(){
            NSLog(@"I am a block!");
        };
        
        //Block的调用
        block();
        
    }
    return 0;
}

紧接着,通过xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp命令拿到编译后的c++文件,添加到项目中。直接查看该文件的尾部


在main函数里面,有很多强制类型转换代码,为了便于理解,去掉这些转换代码(不影响原有的逻辑),将其main函数简化成如下
//【1.2】
struct __main_block_impl_0 {
    
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
    
    //C++语法下,下面的函数是一个类的构造方法,函数名与类名相同,与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;
  }
};

//【1.1】这个函数是block内部封装的代码块执行逻辑
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

            NSLog((NSString *)&__NSConstantStringImpl__var_folders_7__p19yp82j0xd2m_1k8fpr77z40000gn_T_main_65b8ed_mi_0);
        }

//【1.3】
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)};

//main函数
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 

        //【1】-------------- 【1.4】
        void (*block)(void) = &__main_block_impl_0(
                                                   __main_block_func_0,
                                                   &__main_block_desc_0_DATA));

        //【2】
        block->FuncPtr(block);
    }
    return 0;
}

下面来分析一下系统底层的执行的逻辑。
首先,根据oc代码中main 函数里面的第一句代码

//Block的定义
        void (^block)(void) = ^(){
            NSLog(@"I am a block!");
        };

系统会进行步骤【1.1】,也就是会吧Block中的代码块封装到函数static void __main_block_func_0(struct __main_block_impl_0 *__cself){}里面.

接下来的步骤【1.2】,系统会定义结构体struct __main_block_impl_0作为Block的底层数据结构,由于是C++语法下的结构体,因此这个结构体里面可以定义函数,代码中的函数为这个结构体的构造函数__main_block_impl_0()

接下来的【1.3】步骤,系统又定义了结构体static struct __main_block_desc_0,并且生成了一个实例__main_block_desc_0_DATA,用来存放Block的相关描述信息。

最后是【1.4】步骤,系统利用构造函数__main_block_impl_0()生成的对象的地址赋值给block指针。传入的参数有两个,分别为
(1)__main_block_func_0

  • 最后赋值给了__main_block_impl_0->impl->funcPtr

(2)&__main_block_desc_0_DATA

  • 根据结构体static struct __main_block_desc_0构造

这样步骤【1】就结束了。再上一幅图来呈现一下整个过程

步骤【1】流程图

接下来根据根据我们的OC代码

//【2】
        block->FuncPtr(block);

系统会通过步骤【2】完成了block的调用,也就是调用block内部封装的那个函数指针。
block->FuncPtr(block);

⚠️小细节 block->FuncPtr(block);为什么没报错?因为按照我们的代码结构,应该是block->impl->FuncPtr(block);才对。
且看struct __main_block_impl_0 中的第一个成员为struct __block_impl impl;,说明impl是一个结构体,不是指针,所以可以直接把它的内容搬到struct __main_block_impl_0 来理解

因此block->FuncPtr(block); 等价于block->impl->FuncPtr(block);,两种方式实际上都可以拿到FuncPtr进行调用。

至此,Block的底层最简单数据结构就初步分析完了。

相关文章

  • Block笔记(2)—— 底层结构

    上一篇,我们初步认识了Block的一些基本知识。现在,我们来一起挖掘一下Block的底层结构。 紧接着,通过xcr...

  • Block底层原理分析

    iOSBlock底层原理解析 目录 Block底层解析什么是block?block编译转换结构block实际结构b...

  • 5. block

    目录 Block底层解析什么是block?block编译转换结构block实际结构block的类型NSConcre...

  • Block技巧与底层解析

    目录 Block底层解析什么是block?block编译转换结构block实际结构block的类型NSConcre...

  • iOS底层原理 - 窥探Block的本质(一)

    通过窥探Block的底层实现,解答以下问题 1.Block底层数据结构是什么,本质是什么2.Block与其所访问的...

  • BLOCK简单分析

    1、block的本质:是一个结构体,里面有一个isa指针; 2、底层结构:__block_impl、__main_...

  • iOS源码解析:Block的本质<一>

    Block在iOS开发中的用途非常广,今天我们就来一起探索一下Block的底层结构。 1. Block的底层结构 ...

  • 探索Block内部构造

    1. Block的底层结构 以下是一个没有参数和返回值的最简单的Block: 为了探索Block的底层结构,需要将...

  • Block

    1、block的定义和使用 2、Block的底层基本结构 通过clang命令查看编译器是如何实现Block的,在终...

  • OC - Block 详解

    目录1.Block 的基本使用2.Block 的底层数据结构3.Block 的变量捕获机制3.1 auto 类型的...

网友评论

    本文标题:Block笔记(2)—— 底层结构

    本文链接:https://www.haomeiwen.com/subject/mmflxctx.html