Block本质(底层结构&变量捕获)

block本质上也是一个OC对象,它内部也有一个isa指针,block是封装了函数调用以及函数调用环境的OC对象。

Block的底层结构

如下图所示:


block底层结构.png

先在项目中定义一个block,然后执行block,通过命令行clang -rewrite-objc main.m,将OC代码转化为c++代码,看一下block的底层结构。

block底层结构C++对照

现在通过右侧的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)

你可能感兴趣的:(Block本质(底层结构&变量捕获))