11 iOS底层原理 - Block本质探究

废话不多说,老规矩,还是来到面试题:

一,block的原理是什么?本质是什么样的?

带着疑问,咋们一起看看block的底层到底长啥样...

研究本质,我们常用的手段就是,就是将oc的代码通过clang编译成c++的代码,然后通过c++的代码,看看到底都干了啥。

一,研究block编译后C++代码

1. clang编译

定一个block及实现,通过clang编译,看看block底层的数据结构是什么???

- (void)viewDidLoad {
    [super viewDidLoad];
    
    int age = 18;
    void (^myBlock)(void) = ^{
        NSLog(@"myBlock = %d", age);
    };
    myBlock();
}

利用clang在终端编译,我的代码是在ViewController.m里面写的,所以编译这个.m文件就好

& xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m
2. 查看c++代码

直接上图

image.png

通过上图可以得出:

  1. Block实现的原理:
    1> Block实现,Block在底层就是一个指向结构体的指针,
    2> 调用block时,根据Block对应的指针找到相应的函数,进而进行调用,并把自己传进去;
  1. 编译后的代码,Block定义部分也就是=右边的^{}转换中成了一个函数,这个函数接收三个参数:
__ViewController__viewDidLoad_block_impl_0(func, desc, age);

这个函数到底是什么呢??
是一个返回当前结构体类型的函数(类似于oc中的初始化函数),
最终将这些信息存储在了结构体中,这个结构体中具体有啥呢?
接着往下看...

3. block底层数据结构分析

通过下图我们分析一下,block底层的数据结构:

通过图例,可以知道,最后的isa是指向对象的结构体的。
所以得出结论:

结论: block的底层数据结构是一个结构体,本质就是一个OC对象

那么,block的内存布局,简单的用下图就可以表示(红框圈起来的先不用管,后面的博客会讲到):

image.png

其他的成员是不是都可以找到的了,下面说下 FuncPtr这个函数是干什么的吧

4. Block的本质-FuncPtr函数的调用

通过已经存储的FuncPtr地址值,找到具体的方法实现,如图所示:

image.png

找到的这个方法,就是block的{}里面的所有实现。

咋们也可以验证下,这个FuncPtr到底存的是不是这个函数的地址值:

1> 声明block底层数据结构-结构体
struct __block_impl {
  void *isa; // 对象的isa
  int Flags;
  int Reserved;
  void *FuncPtr; // 指向了block里面的实现 { ... }
};

struct __ViewController__viewDidLoad_block_desc_0 {
  size_t reserved;
  size_t Block_size; // 这个block得内存大小
};

struct __ViewController__viewDidLoad_block_impl_0 {
  struct __block_impl impl; // 直接拥有这个结构体变量
  struct __ViewController__viewDidLoad_block_desc_0* Desc; // 这是一个指针,指向另一个结构体的变量
  int age;
};

运行代码:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    int age = 18;
    void (^myBlock)(void) = ^
    {
        NSLog(@"myBlock = %d", age);
    };
    // 将myBlock赋值给一个结构体
    struct __ViewController__viewDidLoad_block_impl_0
    * structBLock =
    (__bridge struct __ViewController__viewDidLoad_block_impl_0 *)myBlock;
    
    myBlock();
}

在myBlock(); 实现处打个断点,就可以找到地址值了,如下图所示:

image.png

通过调试,可以看出:block内存中存储的地址值,就是这个{}里面的地址值。

注意:右侧的堆栈信息是打开了汇编调试,具体如图所示:

image.png

二,Block总结

  1. Block本质是一个OC对象,它内部也存在一个isa指针,底层数据结构是一个结构体;
    1. Block实现的原理:
      1> Block实现,Block在底层就是一个指向结构体的指针,
      2> 调用block时,根据Block对应的指针找到相应的函数,进而进行调用,并把自己传进去。

三,回答文章开头的面试题

一,block的原理是什么?本质是什么样的?
原理:
1> Block实现,Block在底层就是一个指向结构体的指针,
2> 调用block时,根据Block对应的指针找到相应的函数,进而进行调用,并把自己传进去;
本质:
Block本质是一个OC对象,它内部也存在一个isa指针,底层数据结构是一个结构体。

你可能感兴趣的:(11 iOS底层原理 - Block本质探究)