盒子
导航
文章目录
  1. 一、基本语法
  2. 二、解读Block
    1. 1、使用变量
    2. 2、循环引用
  3. 参考资料

Objective-C基础:Block

OC使用Class来捆绑数据和操作行为,但有时候我们并不需要一个像类这么复杂的,而只需要一个单一的,但能像值一样可以在函数之间传递的功能模块来实现一些行为,Block正好提供了这样一种实现。Block是对C、OC、C++都有效的一项语言级别的特性,Block可被视为(但不是)OC对象,这意味着可以将它像其他OC对象一样添加到集合类当中,也可以当成参数传递到一个消息中。Block相当于其他语言中的lambda表达式,即匿名函数。

一、基本语法

Block的基本语法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//声明和使用一个Block
^{
NSLog(@"This is a Block");
}

//使用类似c函数指针一样的语法结构来声明一个变量追踪Block
void (^simpleBlock)(void);
simpleBlock = ^{
NSLog(@"This is a Block");
};

//或者
void (^simpleBlock)(void) = ^{
NSLog(@"This is a Block");
};

//之后便可以像使用c函数一样使用它
simpleBlock();

二、解读Block

Apple在《Blocks Programming Topics》文档中提到:Block对象是一个C句法层面的运行时特性,它很像标准的C函数,但除了可以执行代码之外它还能够绑定变量到堆和栈上,因此它能够在执行时通过维持一组状态来改变行为。Block可作为函数参数来传递、可存储(例如保存到数组)以及应用到多线程当中,它在回调函数中非常有用,因为它既包含可可执行的代码,又能携带这些代码执行时所需要的数据。

Block在随OS X v10.6发布的Xcode开发工具集中的GCC和Clang中得到支持,所以开发者可以在OS X v10.6及其随后版本、iOS 4.0及其随后版本中使用Block。Block的运行时支持实现是开源的,可在LLVM’s compiler-rt subproject repository中获取。鉴于OC和C++都是从C而来,所以Block在设计之初就选择能够同时支持三种语言(C、C++、Objective-C)。

文档附随的一个图展示了Block的语法结构:

1、使用变量

Block的一个强大之处是它能够修改与其在相同上下文范围内的变量,只需要使用__block来前缀修饰该变量即可。Block支持引用三种标准类型变量:

  1. 全局变量,包括静态本地变量
  2. 全局函数(虽然从技术层面来说它不是变量)
  3. 本地变量以及Block参数变量

Block还支持另外两种类型的变量:

  1. 函数层面的使用__block修饰的局部变量
  2. const import(说实话,没读懂。是const修饰的变量?)

变量在Block内的作用规则:

  1. 全局变量是Block可访问的,包括与Block同在一个作用范围内的静态变量
  2. 传递到Block中的参数是可被Block访问的(一句屁话)
  3. 与Block同在一个作用范围内的以const修饰的变量(NSInteger、BOOL)是可访问的: 如果Block有嵌套,每个Block都使用该变量,那么Block中取得的值是离它最近的该变量的状态值
  4. 与Block同在一个作用范围内的以__block修饰的变量在Block内是可访问且可写的: 变量被从栈(如果是在栈中)拷贝到堆中进行修改,Block结束时又被拷贝回去。
  5. 在Block内定义的变量是可读可写的,就像在函数内定义的本地变量一样(又一句屁话)

2、循环引用

Block是可存储的,例如将Block存储到一个数组当中,但是如果Block中有引用self的代码,这将导致循环引用从而导致内存无法释放。因为Block对其内部的所有变量都会保持一个强引用类型指针,而self又对其内数组持有强引用类型指针,数组又对其元素持有强引用类型指针,这使得self既有指向block的强引用,block又有指向self的强引用,解决的办法是声明一个指向self的弱引用,然后在block中使用该弱引用来替代self:

__weak XYZClass *weakSelf = self;

参考资料

Programming with Objective-C》- Working with Blocks