block深入研究

1、写一个OC文件.m文件如下:

#include

int main(int argc, char * argv[]) {
    @autoreleasepool {
        int a = 10;
        void(^block)(void)=^{
            printf("%d",a);
        };
        a = 20;
        block();
    }
}

2、使用clang命令将.m编译成.cpp文件,命令如下:

1、先cd进.m目录下。
2、clang -rewrite-objc xxx.m

3、打开.cpp,可以看到上面.m的代码,转化为下面一坨:

block深入研究_第1张图片
WechatIMG54.jpeg
解释一下这段代码:
等号左边
void(*block)(void)代表一个方法(函数),而block是一个函数指针。
等号右边:
void (*)() 是个强转符号
&__main_block_impl_0表示调用__main_block_impl_0,参数有三个,分别是:
1、__main_block_func_0
2、&__main_block_desc_0_DATA
3、我们声明的参数a

4、那么__main_block_impl_0、__main_block_func_0、__main_block_desc_0_DATA分别是什么东西呢?

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;
  int a;
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  int a = __cself->a; // bound by copy

            printf("%d",a);
        }
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)};
所以说main_block_impl_0是一个结构体,我理解c++的结构体,类似于OC中的类,也就是说这个类有三个参数:
1、对象impl,是__block_impl类的对象;
2、对象Desc ,是__main_block_desc_0类的对象
3、我们声明的参数a
再往下的那个函数应该是个构造函数,用来初始化一个实例用的

5、再看一下__main_block_impl_0中前两个参数(__block_impl和__main_block_desc_0)对应的结构体

struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};
static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
}
在上面的构造初始化block的构造方法中:
 __block_impl的isa是个地址,被赋值成_NSConcreteStackBlock是个32位的地址。
 __block_impl的Flags为0  不知道啥意思
 __block_impl的FuncPtr将会赋值成我们定义的方法,即打印a;

6、调用

((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
可以看到其实就是调用了我们声明的block中的  struct __block_impl impl中的FuncPtr,即打印a

总结一下的话:

1、block是什么?
答:block其实是一个结构体的实例,里面有一个另外一个结构体(这个结构体中存储了block的实现,即打印a)和一个描述,当然还有一个构造函数。
2、block如何调用的呢?
答:当调用block,其实是找到了block中包含方法实现的结构体实例,然后调用的这个实例中的方法。
3、为什么你在调用block之前已经把a赋值为20,打印的却是10呢?
答:我们在把声明a时用__block引起来看一下,有什么变化


block深入研究_第2张图片
4511526629686_.pic_hd.jpg

block深入研究_第3张图片
4521526629746_.pic_hd.jpg

然后你会发现用__block声明的变量,变成了指针传递,并不是上面的值传递,这也是为什么block中修改外部参数的值,需要__block引用的原因。

你可能感兴趣的:(block深入研究)