前言
Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这个新功能“Blocks”。从那开始,Block就出现在iOS和Mac系统各个API中,并被大家广泛使用。一句话来形容Blocks,带有自动变量(局部变量)的匿名函数。
Block在OC中的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct Block_layout { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct Block_descriptor *descriptor; /* Imported variables. */ }; struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *); }; |
从结构图中很容易看到isa,所以OC处理Block是按照对象来处理的。在iOS中,isa常见的就是_NSConcreteStackBlock,_NSConcreteMallocBlock,_NSConcreteGlobalBlock这3种(另外只在GC环境下还有3种使用的_NSConcreteFinalizingBlock,_NSConcreteAutoBlock,_NSConcreteWeakBlockVariable,本文暂不谈论这3种,有兴趣的看看官方文档)
以上介绍是Block的简要实现,接下来我们来仔细研究一下Block的捕获外部变量的特性以及__block的实现原理。
研究工具:clang
为了研究编译器的实现原理,我们需要使用 clang 命令。clang 命令可以将 Objetive-C 的源码改写成 C / C++ 语言的,借此可以研究 block 中各个特性的源码实现方式。该命令是
1 |
clang -rewrite-objc block.c |
目录
- 1.Block捕获外部变量实质
- 2.Block的copy和release
- 3.Block中__block实现原理
一.Block捕获外部变量实质
拿起我们的Block一起来捕捉外部变量吧。
说到外部变量,我们要先说一下C语言中变量有哪几种。一般可以分为一下5种:
- 自动变量
- 函数参数
- 静态变量
- 静态全局变量
- 全局变量
研究Block的捕获外部变量就要除去函数参数这一项,下面一一根据这4种变量类型的捕获情况进行分析。
我们先根据这4种类型
- 自动变量
- 静态变量
- 静态全局变量
- 全局变量
写出Block测试代码。
这里很快就出现了一个错误,提示说自动变量没有加__block,由于__block有点复杂,我们先实验静态变量,静态全局变量,全局变量这3类。测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#import int global_i = 1; static int static_global_j = 2; int main(int argc, const char * argv[]) { static int static_k = 3; int val = 4; void (^myBlock)(void) = ^{ global_i ++; static_global_j ++; static_k ++; NSLog(@"Block中 global_i = %d,static_global_j = %d,static_k = %d,val = %d",global_i,static_global_j,static_k,val); }; global_i ++; static_global_j ++; static_k ++; val ++; NSLog(@"Block外 global_i = %d,static_global_j = %d,static_k = %d,val = %d",global_i,static_global_j,static_k,val); myBlock(); return 0; } |
运行结果
1 2 |
Block 外 global_i = 2,static_global_j = 3,static_k = 4,val = 5 Block 中 global_i = 3,static_global_j = 4,static_k = 5,val = 4 |
这里就有2点需要弄清楚了
1.为什么在Block里面不加__bolck不允许更改变量?
2.为什么自动变量的值没有增加,而其他几个变量的值是增加的?自动变量是什么状态下被block捕获进去的?
为了弄清楚这2点,我们用clang转换一下源码出来分析分析。
(main.m代码行37行,文件大小832bype, 经过clang转换成main.cpp以后,代码行数飙升至104810行,文件大小也变成了3.1MB)
源码如下
前言
Blocks是C语言的扩充功能,而Apple 在OS X Snow Leopard 和 iOS 4中引入了这个新功能“Blocks”。从那开始,Block就出现在iOS和Mac系统各个API中,并被大家广泛使用。一句话来形容Blocks,带有自动变量(局部变量)的匿名函数。
Block在OC中的实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
struct Block_layout { void *isa; int flags; int reserved; void (*invoke)(void *, ...); struct Block_descriptor *descriptor; /* Imported variables. */ }; struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *); }; |
从结构图中很容易看到isa,所以OC处理Block是按照对象来处理的。在iOS中,isa常见的就是_NSConcreteStackBlock,_NSConcreteMallocBlock,_NSConcreteGlobalBlock这3种(另外只在GC环境下还有3种使用的_NSConcreteFinalizingBlock,_NSConcreteAutoBlock,_NSConcreteWeakBlockVariable,本文暂不谈论这3种,有兴趣的看看官方文档)
以上介绍是Block的简要实现,接下来我们来仔细研究一下Block的捕获外部变量的特性以及__block的实现原理。
研究工具:clang
为了研究编译器的实现原理,我们需要使用 clang 命令。clang 命令可以将 Objetive-C 的源码改写成 C / C++ 语言的,借此可以研究 block 中各个特性的源码实现方式。该命令是
1 |
clang -rewrite-objc block.c |
目录
- 1.Block捕获外部变量实质
- 2.Block的copy和release
- 3.Block中__block实现原理
一.Block捕获外部变量实质
拿起我们的Block一起来捕捉外部变量吧。
说到外部变量,我们要先说一下C语言中变量有哪几种。一般可以分为一下5种:
- 自动变量
- 函数参数
- 静态变量
- 静态全局变量
- 全局变量
研究Block的捕获外部变量就要除去函数参数这一项,下面一一根据这4种变量类型的捕获情况进行分析。
我们先根据这4种类型
- 自动变量
- 静态变量
- 静态全局变量
- 全局变量
写出Block测试代码。
这里很快就出现了一个错误,提示说自动变量没有加__block,由于__block有点复杂,我们先实验静态变量,静态全局变量,全局变量这3类。测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#import int global_i = 1; static int static_global_j = 2; int main(int argc, const char * argv[]) { static int static_k = 3; int val = 4; void (^myBlock)(void) = ^{ global_i ++; static_global_j ++; static_k ++; NSLog(@"Block中 global_i = %d,static_global_j = %d,static_k = %d,val = %d",global_i,static_global_j,static_k,val); }; global_i ++; static_global_j ++; static_k ++; val ++; NSLog(@"Block外 global_i = %d,static_global_j = %d,static_k = %d,val = %d",global_i,static_global_j,static_k,val); myBlock(); return 0; } |
运行结果
1 2 |
Block 外 global_i = 2,static_global_j = 3,static_k = 4,val = 5 Block 中 global_i = 3,static_global_j = 4,static_k = 5,val = 4 |
这里就有2点需要弄清楚了
1.为什么在Block里面不加__bolck不允许更改变量?
2.为什么自动变量的值没有增加,而其他几个变量的值是增加的?自动变量是什么状态下被block捕获进去的?
为了弄清楚这2点,我们用clang转换一下源码出来分析分析。
(main.m代码行37行,文件大小832bype, 经过clang转换成main.cpp以后,代码行数飙升至104810行,文件大小也变成了3.1MB)
源码如下