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)

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容