1、写一个OC文件.m文件如下:
#include<stdio.h>
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的代码,转化为下面一坨:
解释一下这段代码:
等号左边
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声明的变量,变成了指针传递,并不是上面的值传递,这也是为什么block中修改外部参数的值,需要__block引用的原因。