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 somethingprint("All done, clean up here")}guard let item = item else {// need throws the error outthrow MyError.notExist}guard item.count > maxNumber else {// need throws the error outthrow 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
里的代码,这样就保证了不管发生什么,最后都会将文件关闭。
- 我们将