美文网首页原理篇iOS 技术笔记程序员
【iOS】简述下OC block的实现

【iOS】简述下OC block的实现

作者: Yaso | 来源:发表于2017-07-29 19:25 被阅读135次

block 实际上是OC 对闭包closure的实现

block的数据结构

先来看下block的结构示意图:

block的数据结构

各组成部分含义:

  1. isa:该对象是什么
  2. flags:block附加信息
  3. reserve:保留变量
  4. invoke:函数实现指针
  5. descriptor:block 描述符,主要是block的一些附加信息
  6. variables:capture过来的变量

这样来看的话,block就是函数 + 数据,即持有着一些数据的函数,编译后生成相应的结构体和函数指针,结构体保存着数据

block的三种类型

在OC中block的类型分为三类:

  1. _NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。
  2. _NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。
  3. _NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。

以下说明几点需要注意的:

  1. _NSConcreteGlobalBlock 是全局静态block,结构体存储在数据区。
  2. 常见的是有捕获外部变量的_NSConcreteStackBlock,需要注意的是如果这种类型的block 定义在函数内部,当函数执行完毕,退栈的时候会将该block结构体所占的内存空间释放掉,这样再引用的话会报错。
  3. _NSConcreteMallocBlock 通常不会在源码中直接出现,OC ARC下会对_NSConcreteStackBlock 进行优化,将其copy到堆上,转换成_NSConcreteMallocBlock,所以无特殊处理,OC中将只会有1,3两种类型block
  4. _NSConcreteStackBlock捕获的局部变量,如不加_block修饰符,将会把变量copy一份到其结构体中,所以才会在内部修改不影响外部变量,加_block修饰之后,结构体中会添加一个__Block_byref_i_0 的结构体,且复制的是变量地址,达到可以修改外部变量的效果。关于这部分详细:这里

block的内存测试

下面简要的看几个例子,分析下其是否生效,即生效的前提,每个例子的答案选项都有4个:

  1. always works
  2. only works with ARC
  3. only works without ARC
  4. never works
Example A:
void exampleA() {
  char a = 'A';
  ^{
    printf("%cn", a);
  }();
}
Example B:
void exampleB_addBlockToArray(NSMutableArray *array) {
  char b = 'B';
  [array addObject:^{
    printf("%cn", b);
  }];
}

void exampleB() {
  NSMutableArray *array = [NSMutableArray array];
  exampleB_addBlockToArray(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}
Example C:
void exampleC_addBlockToArray(NSMutableArray *array) {
  [array addObject:^{
    printf("Cn");
  }];
}

void exampleC() {
  NSMutableArray *array = [NSMutableArray array];
  exampleC_addBlockToArray(array);
  void (^block)() = [array objectAtIndex:0];
  block();
}
Example D:
typedef void (^dBlock)();

dBlock exampleD_getBlock() {
  char d = 'D';
  return ^{
    printf("%cn", d);
  };
}

void exampleD() {
  exampleD_getBlock()();
}
Example E:
typedef void (^eBlock)();

eBlock exampleE_getBlock() {
  char e = 'E';
  void (^block)() = ^{
    printf("%cn", e);
  };
  return block;
}

void exampleE() {
  eBlock block = exampleE_getBlock();
  block();
}
  • A:always works,此block类型是_NSConcreteStackBlock,但block调用在函数体内,函数释放前已经执行完毕,所以无论在栈上还是堆上都可以正常执行。
  • B:only works with ARC,非ARC的话,block内存空间在函数exampleB_addBlockToArray的栈上,此函数执行完毕,退栈时候内存空间清空,引用报错。ARC下会被转换成_NSConcreteMallocBlock,copy到堆上所以生效。
  • C:always works,此block类型是_NSConcreteGlobalBlock,存储在数据区,所以一直生效。
  • D:only works with ARC,同B,但编译器无法编译,会报错。
  • E:only works with ARC,同D,但编译器不会报错,更需注意。

相关文章

  • 【iOS】简述下OC block的实现

    block 实际上是OC 对闭包closure的实现 block的数据结构 先来看下block的结构示意图: 各组...

  • swift 调用 OC中的block

    OC中声明block; OC中实现block swift中实现

  • Block常见用法的理解

    How To Use OC Block Part1 Block简述 Block作为语言特性 在Mac OS X 1...

  • 探寻block的本质

    转自:探寻block的本质拓展:探寻OC对象的本质iOS底层原理总结 - 关联对象实现原理iOS底层原理总结 - ...

  • iOS-2 Block

    block块 系列文章: iOS Block浅浅析 - 简书 iOS Block实现原理 iOS Block __...

  • iOS Block存储域及循环引用

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block __block说明符...

  • 深入 Block

    Block 前言 Block是OC中对C语言的扩展功能,是一种带有自动变量的匿名函数,Block在OC中的实现,点...

  • iOS原理(五)----block

    iOS原理(五)----block block的本质 block本质上也是一个OC对象,它内部也有个isa指针, ...

  • iOS Block __block说明符

    系列文章:iOS Block概念、语法及基本使用iOS Block实现原理iOS Block存储域及循环引用 上一...

  • iOS开发 - WebViewJavascriptBridge分

    强烈推荐:iOS源码补完计划-WebViewJavascriptBridge实现原理 iOS下JS与OC互相调用(...

网友评论

    本文标题:【iOS】简述下OC block的实现

    本文链接:https://www.haomeiwen.com/subject/dmpclxtx.html