面试题:block的原理是怎样的?本质是什么?
block是封装了函数调用及其函数调用环境的OC对象,本质就是oc对象,内部存在isa指针。
block本质:也是一个OC对象,它内部也有isa指针。
block是封装了函数调用以及函数调用环境的OC对象。
通过命令 xcrun -sdk iphoneos -arch arm64 -rewrite-objc main.m 得出对应main.m文件的c++源码:
int age = 20;
void(^block)(void) = ^{
NSLog("Hello, word");
} block();
底层实现大致如下:底层是一个block_impl_0的结构体,里面包含一个impl的结构体,该结构体中存在isa指针,FuncPtr是要执行的内部方法地址;desc结构体里面包含默认值为0的reserverd,和表示结构体大小的block_size;age是捕获进来的变量。
block的变量捕获
为了保证block内部能够正常访问外部的变量,block有个变量捕获机制
auto:自动变量,离开作用域就会自动销毁
static:
下面方法中的self有没有被捕获,即是不是局部变量?
是局部变量,因为方法等价于-(void)test:(id)self cmd:(SEL)cmd; self是作为一个参数传进来的,是局部变量。
下面的_name会被捕获吗?
它是先捕获self,再去调用self里面的name,因为_name=self.name
block类型:
block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型(因为本质是OC对象,所以可以调用class方法和isa指针,还有就是isa指针也是因为它继承于nsobject)。
类型一切以运行时为准;clang 生成c++;llvm x.0 可能生成一些中间文件
应用程序的内存分配从高到低地址是:
栈区-->堆区-->数据区域(.data区)-->程序区域(.text区)
栈区存放_NSConcreteStackBlock;
堆区存放_NSConcreteMallocBlock
数据区域存放_NSConcreteGlobalBlock
特别注意:在打印的时候有可能出现结果跟预想不一致的情况,这需要我们手动将ARC改成MRC,因为ARC自动管理可能给我们做了很多工作,导致跟预期不一致。
这个栈block打印出来是一串垃圾数据,原因就是因为栈block在栈区,会被销毁掉,所以打印它的数据是垃圾数据。解决这个问题需要将栈block通过copy转为堆block,如下
全局block调用copy后还是全局block:
结论:每一种类型的block调用copy后的结果如下:
网友评论