Swift中defer的使用

defer基本理解

在Swift中,defer所声明的block会在当前代码执行退出后被调用。正因为它提供了一种延时调用的方式,所以一般会被用来做资源释放或者销毁,这在某个函数有多个返回出口的时候特别有用。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
func operateOnFile(descriptor: Int32) {
let fileHandle = FileHandle(fileDescriptor: descriptor)
defer { fileHandle.closeFile() }
let data = fileHandle.readDataToEndOfFile()

if /* onlyRead */ { return }

let shouldWrite = /* 是否需要写文件 */
guard shouldWrite else { return }

fileHandle.seekToEndOfFile()
fileHandle.write(someData)
}

需要特别注意的是defer的作用域。

在Swift Programming Language 关于defer的描述:

A defer statement is used for executing code just before transferring program control outside of the scope that the defer statement appears in.

defer是在当前 scope 退出的时候调用而不是在函数退出的时候调用。

defer和闭包

虽然defer后面跟了一个闭包,但是它更多地像是一个语法糖,和我们所熟知的闭包特性不一样,并不会持有里面的值。比如:

1
2
3
4
5
6
7
8
9
func foo() {
var number = 1
defer { print("Statement 2: \(number)") }
number = 100
print("Statement 1: \(number)")
}
// 输出:
//Statement 1: 100
//Statement 2: 100

defer中如果要依赖某个变量值时,需要自行进行复制:

1
2
3
4
5
6
7
8
9
10
func foo() {
var number = 1
var closureNumber = number
defer { print("Statement 2: \(closureNumber)") }
number = 100
print("Statement 1: \(number)")
}
// 输出:
// Statement 1: 100
// Statement 2: 1

从语言设计上来说,defer的目的就是进行资源清理和避免重复的返回前需要执行的代码,而不是用来以取巧地实现某些功能。这样做只会让代码可读性降低。