block本质上也是一个OC对象,它内部也有一个isa指针,block是封装了函数调用以及函数调用环境的OC对象。
Block的底层结构
如下图所示:
block底层结构.png
先在项目中定义一个block,然后执行block,通过命令行clang -rewrite-objc main.m
,将OC代码转化为c++代码,看一下block的底层结构。
现在通过右侧的OC代码,对照看一下c++源码。
void(^block)(void) = ^{
NSLog(@"Hello, World!");
};
block();
//定义block
void(*block)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
//执行block内部代码
((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block);
block就相当于__main_block_impl_0
;执行block,就相当于__block_impl->FuncPtr
,找到block中封装的函数FuncPtr,然后执行。
Block的变量捕获
为了保证block内部能够正常访问内部的变量,block有个变量捕获机制
block变量捕获.png
auto变量存放在动态存储区,随着生命周期的结束而立即释放。只有函数的局部变量才能定义为auto类型。
static变量存放在静态存储区,在程序整个运行期间都不释放。在函数内定义的静态变量为静态局部变量,在函数外定义的静态变量为静态全局变量。
以下分别为Block中引用auto类型局部变量,static局部变量以及全局变量,通过OC代码编译成c++源码的对照
block变量捕获C++对照.png
运行结果:
Block[1635:48861] age is 10, height is 20, weight is 110
上图可以看出age和height变量都被捕获到block中,age是值捕获,height是值捕获,全部变量weight没有被捕获。
对象类型的auto变量
当block内部访问了对象类型的auto变量时
-
如果block是在栈上,将不会对auto变量产生强引用
-
如果block被拷贝到堆上
会调用block内部的copy函数
copy函数内部会调用_Block_object_assign函数
_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用 -
如果block从堆上移除
会调用block内部的dispose函数
dispose函数内部会调用_Block_object_dispose函数
_Block_object_dispose函数会自动释放引用的auto变量(release)
网友评论