1、Defer
在一些语言中,有
try/finally
这样的控制语句,比如 Java。这种语句可以让我们在finally
代码块中执行必须要执行的代码,不管之前怎样的兴风作浪。在 Swift 2.0 中,Apple 提供了defer
关键字,让我们可以实现同样的效果。func checkSomething() { print("CheckPoint 1") doSomething() print("CheckPoint 4") } func doSomething() { print("CheckPoint 2") defer { print("Clean up here") } print("CheckPoint 3") } // CheckPoint 1, CheckPoint 2, CheckPoint 3, Clean up here, CheckPoint 4 checkSomething()
- 上述示例可以看到,在打印出
CheckPoint 2
之后并没有打印出Clean up here
,而是CheckPoint 3
,这就是defer
的作用,它对进行了print("Clean up here")
延迟。
- 上述示例可以看到,在打印出
在你的代码块就要结束前。如果你使用了
defer
。在其之中的代码就会运行。等于说,给了你最后的机会来进行一些处理。如果你熟悉 BDD 或者 TDD,那么你可以参考他们中的aferAll
机制。func myFunction() throws { defer { // No matter what happened I need do something print("All done, clean up here") } guard let item = item else { // need throws the error out throw MyError.notExist } guard item.count > maxNumber else { // need throws the error out throw MyError.outOfRange } // do something with item // ... }
如果你有多个
defer
语句,他们在执行的顺序会和栈一样,最后一个进,第一个出。
2、Defer 示例
我们再来看一个 I/O 的示例
func writeSomething() { let file = OpenFile() let iostatus = fetchIOStatus() guard ioStatus != "error" else { return } file.write() closeFile(file) }
- 上述示例是一个 I/O 操作的伪代码,如果获取到的
ioStatus
正常,那么该方法没有问题,如果ioStatus
取到的是error
,那么会被guard
语句抓到执行return
操作,这样的话closeFile(file)
就永远都不会执行了,一个严重的 Bug 就这样产生了。
- 上述示例是一个 I/O 操作的伪代码,如果获取到的
下面我们看看如何用
defer
来解决这个问题。func writeSomething() { let file = OpenFile() defer { closeFile(file) } let ioStatus = fetchIOStatus() guard ioStatus != "error" else { return } file.write() }
- 我们将
closeFile(file)
放在defer
代码块里,这样即使ioStatus
为error
,在执行return
前会先执行defer
里的代码,这样就保证了不管发生什么,最后都会将文件关闭。
- 我们将