延迟语句和 return 之前的语句有什么区别?

What's the difference between a defer statement and a statement right just before return?

这有什么区别:

_ = navigationController?.popViewController(animated: true)

defer {
    let rootVC = navigationController?.topViewController as? RootViewVC
    rootVC?.openLink(url: url)
}
return

还有这个:

_ = navigationController?.popViewController(animated: true)

let rootVC = navigationController?.topViewController as? RootViewVC
rootVC?.openLink(url: url)
return

A​​pple 的 swift 指南说:“您使用 defer 语句在代码执行离开当前代码块之前执行一组语句。 ”,但我还是不太明白。

在你的示例中实际上没有区别,但请看这个:

func foo(url: URL) -> Int
    let fileDescriptor : CInt = open(url.path, O_EVTONLY);
    defer {
      close(fileDescriptor)
    }
    guard let bar = something1() else { return 1 }
    guard let baz = something2() else { return 2 }
    doSomethingElse(bar, baz)
    return 3
}

close(fileDescriptor)总是执行,不管函数returns.

在哪一行

使用 defer 可以避免在函数结束时进行条件清理。

考虑这个例子:

class Demo {
    var a : String
    init(_ a:String) {
        self.a = a
    }
    func finish() {
        print("Finishing \(a)")
    }
}

func play(_ n:Int) {
    let x = Demo("x")
    defer { x.finish() }
    if (n < 2) {return}
    let y = Demo("y")
    defer { y.finish() }
    if (n < 3) {return}
    let z = Demo("z")
    defer { z.finish() }
}

play(1)
play(2)
play(3)

函数 play 根据其参数创建一个、两个或三个 Demo 对象,并在 运行 的末尾对它们调用 finish。如果中间的函数 returns,defer 语句不会执行,并且不会为从未创建的对象调用 finish

对此的替代方法需要使用选项:

func play(_ n:Int) {
    var x:Demo? = nil
    var y:Demo? = nil
    var z:Demo? = nil
    x = Demo("x")
    if (n >= 2) {
        y = Demo("y")
    }
    if (n >= 3) {
        z = Demo("z")
    }
    x?.finish()
    y?.finish()
    z?.finish()
}

这种方法将所有声明放在顶部,并强制您稍后解包可选值。另一方面,带有 defer 的代码允许您在执行初始化的代码附近编写清理代码。

What's the difference between a defer statement and a statement right just before return?

世界上所有的差异。 defer 语句在 return 之后执行!这使您可以完成其他方法无法完成的事情。

例如,您可以 return 一个值,然后 更改该值。 Apple 经常使用这个技巧;例如,这里是序列文档中的代码,展示了如何编写自定义序列:

struct Countdown: Sequence, IteratorProtocol {
    var count: Int

    mutating func next() -> Int? {
        if count == 0 {
            return nil
        } else {
            defer { count -= 1 }
            return count
        }
    }
}

如果你把它写成

            count -= 1
            return count

...它会坏掉;我们不想递减 count 然后 return 它,我们想 return count 然后递减它。

此外,正如已经指出的,无论如何退出,defer 语句都会执行。无论您退出当前 scope,它都有效,这可能根本不涉及 returndefer 适用于函数体、while 块、if 结构、do 块等。单个 return 不是退出此类范围的唯一方法!你的方法中可能有多个 return,and/or 你可能会抛出一个错误,and/or 你可能有一个 break,等等,或者你可能只是自然到达范围的最后一行; defer 在所有可能的情况下都会执行。编写相同的代码 "by hand" 以覆盖所有可能的出口,这很容易出错。

defer 语句用于恰好在执行离开最近范围之前执行一段代码。

例如:

func defer()  { 
 print("Beginning") 
 var value: String? 
 defer { 
    if let v = value { 
        print("Ending execution of \(v)")
    } 
 } 
 value = "defer function" 
 print("Ending")
}

将打印的第一行是:开始

将打印的第二行是:结束

打印的最后一行是:Ending execution of defer function。