1.C++源码预览
int a = 10;
void(^block)(void) = ^{
NSLog(@"Hello, World! %d",a);
};
block();
通过clang -rewrite-objc main.m
生成cpp文件
// 代码变为
int a = 10;
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a));
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
// 一看是不是有点蒙蔽我们去掉强制装换来看一下
int a = 10;
void(*block)(void) =
&__main_block_impl_0(__main_block_func_0, &__main_block_desc_0_DATA, a);
// 这一句就是调用一个c的方法,并取这个方法的地址,赋值给一个block类型的指针
block->FuncPtr(block);
// 拿到这个block一个成员的FuncPtr方法并调用
先看下这个东西__main_block_impl_0
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;
}
};
__main_block_impl_0 其实就是block的本质一个结构体,
里面有个同名字的构造方法返回本身(c++语法).
构造方法里
impl.isa = &_NSConcreteStackBlock; // 确定isa指向
impl.Flags = flags; // 标识为0
impl.FuncPtr = fp; // 代码块方法
Desc = desc; // 描述
构造函数传进来的参数都赋值给了__main_block_impl_0结构体的成员impl,
impl也是一个结构体
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
看到没有block也持有一个void *isa指针,所以说block是一个oc对象.
之后看下这个东西__main_block_func_0
就是调用构造函数传进去的参数
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int a = __cself->a; // 此参数可以从上面代码看出,是传的block
NSLog((NSString *)&__NSConstantStringImpl__var_folders_sf_9x41px110wz4nbxh71bwvwzr0000gp_T_main_dd6554_mi_0,a);
}
这里正好是我们的打印代码,block里面的代码都会放在这里面等待调用
所以说block其实是一个结构体,保存一个函数指针,指向我们写的代码块既一个c函数,等待我们调用.
- block本质也是一个oc对象,内部也有一个isa指针.
- block是封装了函数调用及函数调用环境的oc对象.
2.捕获变量
![](https://img.haomeiwen.com/i1646251/d135a23b1ffc2587.png)
// 大括号外面
int age3 = 10; // 全局变量
static int age4 = 10; // 全局变量静态
// 大括号外面
{
auto int age1 = 10; // oc默认是auto变量
static int age2 = 10; // 局部静态
}
通过源码看下两者的却别
#import <Foundation/Foundation.h>
int age3 = 30;
static int age4 = 30;
int main(int argc, const char * argv[]) {
@autoreleasepool {
auto int age1 = 10;
static int age2 = 20;
void(^block)(void) = ^{
NSLog(@"Hello, World! %d%d%d%d",age1,age2,age3,age4);
};
block();
}
return 0;
}
c++
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int age1;
int *age2;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _age1, int *_age2, int flags=0) : age1(_age1), age2(_age2) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int age1 = __cself->age1; // bound by copy
int *age2 = __cself->age2; // bound by copy
NSLog((NSString *)&__NSConstantStringImpl__var_folders_sf_9x41px110wz4nbxh71b
wvwzr0000gp_T_main_b2cff9_mi_0,age1,(*age2),age3,age4);
}
从上面源码看出,只捕获了age1和age2,而age3和age4是直接用的
age1是值,age2是指针,所以age1捕获的是值age2捕获的是指针.
3.block类型
![](https://img.haomeiwen.com/i1646251/2fb923fe48909753.jpg)
![](https://img.haomeiwen.com/i1646251/b771f8751cd3b4aa.png)
auto int age1 = 10;
void(^block)(void) = ^{
NSLog(@"Hello, World! %d%d%d%d",age1);
};
block();
NSLog(@"%@",[block class]);
[block class] // 可以直接获取block类型,从这一点也说明block是一个oc对象
arc下系统会自动帮你把block从栈上拷贝到堆上
既调用[block copy]
网友评论