废话不多说,老规矩,还是来到面试题:
一,block的原理是什么?本质是什么样的?
带着疑问,咋们一起看看block的底层到底长啥样...
研究本质,我们常用的手段就是,就是将oc的代码通过clang编译成c++的代码,然后通过c++的代码,看看到底都干了啥。
一,研究block编译后C++代码
1. clang编译
定一个block及实现,通过clang编译,看看block底层的数据结构是什么???
- (void)viewDidLoad {
[super viewDidLoad];
int age = 18;
void (^myBlock)(void) = ^{
NSLog(@"myBlock = %d", age);
};
myBlock();
}
利用clang在终端编译,我的代码是在ViewController.m里面写的,所以编译这个.m文件就好
& xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc ViewController.m
2. 查看c++代码
直接上图
image.png通过上图可以得出:
- Block实现的原理:
1> Block实现,Block在底层就是一个指向结构体的指针,
2> 调用block时,根据Block对应的指针找到相应的函数,进而进行调用,并把自己传进去;
- 编译后的代码,Block定义部分也就是=右边的^{}转换中成了一个函数,这个函数接收三个参数:
__ViewController__viewDidLoad_block_impl_0(func, desc, age);
这个函数到底是什么呢??
是一个返回当前结构体类型的函数(类似于oc中的初始化函数),
最终将这些信息存储在了结构体中,这个结构体中具体有啥呢?
接着往下看...
3. block底层数据结构分析
通过下图我们分析一下,block底层的数据结构:
通过图例,可以知道,最后的isa是指向对象的结构体的。
所以得出结论:
结论: block的底层数据结构是一个结构体,本质就是一个OC对象
那么,block的内存布局,简单的用下图就可以表示(红框圈起来的先不用管,后面的博客会讲到):
image.png其他的成员是不是都可以找到的了,下面说下 FuncPtr这个函数是干什么的吧
4. Block的本质-FuncPtr函数的调用
通过已经存储的FuncPtr地址值,找到具体的方法实现,如图所示:
image.png找到的这个方法,就是block的{}里面的所有实现。
咋们也可以验证下,这个FuncPtr到底存的是不是这个函数的地址值:
1> 声明block底层数据结构-结构体
struct __block_impl {
void *isa; // 对象的isa
int Flags;
int Reserved;
void *FuncPtr; // 指向了block里面的实现 { ... }
};
struct __ViewController__viewDidLoad_block_desc_0 {
size_t reserved;
size_t Block_size; // 这个block得内存大小
};
struct __ViewController__viewDidLoad_block_impl_0 {
struct __block_impl impl; // 直接拥有这个结构体变量
struct __ViewController__viewDidLoad_block_desc_0* Desc; // 这是一个指针,指向另一个结构体的变量
int age;
};
运行代码:
- (void)viewDidLoad {
[super viewDidLoad];
int age = 18;
void (^myBlock)(void) = ^
{
NSLog(@"myBlock = %d", age);
};
// 将myBlock赋值给一个结构体
struct __ViewController__viewDidLoad_block_impl_0
* structBLock =
(__bridge struct __ViewController__viewDidLoad_block_impl_0 *)myBlock;
myBlock();
}
在myBlock(); 实现处打个断点,就可以找到地址值了,如下图所示:
image.png通过调试,可以看出:block内存中存储的地址值,就是这个{}里面的地址值。
注意:右侧的堆栈信息是打开了汇编调试,具体如图所示:
image.png二,Block总结
- Block本质是一个OC对象,它内部也存在一个isa指针,底层数据结构是一个结构体;
- Block实现的原理:
1> Block实现,Block在底层就是一个指向结构体的指针,
2> 调用block时,根据Block对应的指针找到相应的函数,进而进行调用,并把自己传进去。
三,回答文章开头的面试题
一,block的原理是什么?本质是什么样的?
原理:
1> Block实现,Block在底层就是一个指向结构体的指针,
2> 调用block时,根据Block对应的指针找到相应的函数,进而进行调用,并把自己传进去;
本质:
Block本质是一个OC对象,它内部也存在一个isa指针,底层数据结构是一个结构体。
网友评论