Swift Defer 延迟调用

1、Defer

  • 在一些语言中,有 try/finally 这样的控制语句,比如 Java。这种语句可以让我们在 finally 代码块中执行必须要执行的代码,不管之前怎样的兴风作浪。在 Swift 2.0 中,Apple 提供了 defer 关键字,让我们可以实现同样的效果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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 机制。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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 的示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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 就这样产生了。
  • 下面我们看看如何用 defer 来解决这个问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    func writeSomething() {

    let file = OpenFile()

    defer {
    closeFile(file)
    }

    let ioStatus = fetchIOStatus()

    guard ioStatus != "error" else {
    return
    }

    file.write()
    }
    • 我们将 closeFile(file) 放在 defer 代码块里,这样即使 ioStatuserror,在执行 return 前会先执行 defer 里的代码,这样就保证了不管发生什么,最后都会将文件关闭。
文章目录
  1. 1. 1、Defer
  2. 2. 2、Defer 示例
隐藏目录