iOS:Block的本质

作者: Sunxb | 来源:发表于2019-04-04 17:44 被阅读1次

我们项目中经常使用block来进行回调传值,之前我对block的认识也就仅仅的停留在基础的层面,包括简单的使用和一些基本的避免循环引用的方法,这篇博客是我在对block进行了更深一层的学习之后的记录和总结,希望对大家有所帮助。

Block的本质

新建一个命令行项目,写一个简单的block如下面所示。

void (^myBlock)(void) = ^{
    NSLog(@"11");
};        
myBlock();

使用clang工具把main.m文件编译为cpp文件。main函数变成了下面这个样子

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

        void (*myBlock)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));

        ((void (*)(__block_impl *))((__block_impl *)myBlock)->FuncPtr)((__block_impl *)myBlock);


    }
    return 0;
}

里面有很多类型转换的代码,但是不难看出,我们的block被编译成了一个__main_block_impl_0类型的变量,我们可以搜索一下,这是一个结构体。

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
    
  __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;
  }
};

这个__main_block_impl_0结构体有两个属性,一个是__block_impl类型的结构体,一个是指向__main_block_desc_0结构体的指针。我们一个一个的看。

//__block_impl 结构体
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

我们可以看到这个结构体有一个isa指针,同时在__main_block_impl_0这个结构体中是直接包含__block_impl结构体,从内存结构中其实这个isa指针就在__main_block_impl_0里面,也就是说block被编译成了一个拥有isa指针的结构体。了解过isa的应该知道,这算是oc对象的一个标志了,那也就是说block其实也是一个oc的对象。

我们继续看__main_block_impl_0内部

  __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;
  }

这是一个初始化的方法,因为这是c++代码嘛,c语言的结构体应该是不可以这样写的。

只要是给这个__block_impl类型的impl赋值,这里我们先主要看这个fp指针。

从编译之后main函数中看出来,在初始化__main_block_impl_0的时候传进去的参数是一个__main_block_func_0

// __main_block_func_0
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_zx_pr_dx33d329d7xxgk9kgjdw80000gp_T_main_85af40_mi_0);
}

可以看出来这是我们block回调执行的方法,也就是说impl.FuncPtr指向了block的回调。

__main_block_impl_0还有一个Desc参数,我们可以在文件中查一下。

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};

reserved是一个保留字段,Block_size就是记录我们这个block占内存的大小。

本节小结
Block本质就是一个OC对象,内部有isa指针。
Block是封装了函数调用和函数调用的环境的OC对象。

我们来个草图来梳理一下最简单的block的内部结构。

block图示.png

相关文章

  • block系列文章总结

    iOS源码解析:Block的本质<一>iOS源码解析:Block的本质<二>Objective C block背后...

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

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

  • Objective-C的本质(6)——Block本质

    参考:iOS-Block本质iOS底层原理总结 - 探寻block的本质(一)iOS底层原理总结 - 探寻bloc...

  • iOS底层原理总结 - 探寻block的本质(一)

    iOS底层原理总结 - 探寻block的本质(一) iOS底层原理总结 - 探寻block的本质(一)

  • Block

    xx_cc iOS底层原理总结 - 探寻block的本质(一)iOS底层原理总结 - 探寻block的本质(二) ...

  • iOS原理(五)----block

    iOS原理(五)----block block的本质 block本质上也是一个OC对象,它内部也有个isa指针, ...

  • iOS-Block本质

    iOS-Block本质 参考篇:iOS-Block浅谈[https://www.jianshu.com/p/25a...

  • iOS-Block本质

    参考篇:iOS-Block浅谈 前言:本文简述Block本质,如有错误请留言指正。 第一部分:Block本质 Q:...

  • 底层原理之Block

    iOS 面试集合之block#### block1. 本质:block是个结构体对象,封装了函数调用```obje...

  • 探寻block的本质

    转自:探寻block的本质拓展:探寻OC对象的本质iOS底层原理总结 - 关联对象实现原理iOS底层原理总结 - ...

网友评论

    本文标题:iOS:Block的本质

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