Block实现-block的实质

Block的实质:

#import <Foundation/Foundation.h>
int main() {
    void(^blk)(void)=^{printf("Block");};
    blk();
    return 0;
}

使用clang将该block转换。

clang -rewrite-objc  源代码文件

转换后形成的block文件是:

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

 

 
  

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;

 
  

  }

 
  

};

 
  

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {

 
  

printf("Block");}

 
  

 

 
  

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

 
  

int main() {

 
  

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

 
  

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

 
  

    return 0;

 
  

}



下面我们就来具体分析一下这些源代码:

首先我们看到

^{printf("Block");};

转换后称为

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
printf("Block");}

如上所示的,block使用的匿名函数,其实被转换成c语言函数处理,,该函数中 的_cself是_main_block_func_0结构体的指针。

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;

具有两个成员变量,_block_impld 代码如下:

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

第二个成员变量是

__main_block_desc_0:其代码如下:

 
  

static struct __main_block_desc_0 {

  size_t reserved;

  size_t Block_size;

}

 
 

这个包含了今后版本升级所需的区域以及block的大小。

下面我们来看一下初始化含有这些数据的结构体的代码:

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

在这里面NSConcreteStackBlock用来初始化,接下来我们对构造函数的调用:

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

因为转换太多实在太难以理解,所以我们去掉转换的部分,这样得到的结果是:

struct _main_block_impl_0 tmp=_main_block_impl_0(_main_block_func_0,&_main_block_desc_DATA);
struct _main_block_impl_0  *blk=&tmp;

这样一来我们可以清楚的看到,

void(^blk)(void)=^{printf("Block");};

这个语句的实现了_main_block_impl_0的两个变量,一个功能函数,一个desc,将block语法生成的block类型对象再赋值给blk,相当于将实例的指针赋值给blk,_main_block_desc_DATA主要是对_main_block_impl_0的结构体实例的大小进行初始化.

blk();

这部分代码转换成为了

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

我们一样去掉转换的部分得到:

(*blk)->impl.Funcptr(blk)

这其实是最简单的函数指针调用函数,正如我们刚才确认的那样,在调用函数中我们看出block是作为参数进行传递的。

那么到底什么是NSConcreteStackBlock呢?

为了理解他首先我们需要理解oc类和对象的实质,其实,所谓的block就是对象,“id”这一变量用于存储oc对象,NSConcreteStackBlock就相当于c结构体实例,将block作为oc对象处理时,该类的信息就放置于NSConcreteStackBlock处。

你可能感兴趣的:(Block实现-block的实质)