什么是正确的只是返回前defer语句和语句之间的区别?

问题描述 投票:12回答:4

这是什么之间的区别:

_ = 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

苹果的迅速方针说:“你使用defer语句执行代码离开当前代码块之前执行一组语句。 ”,但我还是不太明白。

ios swift deferred
4个回答
30
投票

什么是正确的只是返回前defer语句和语句之间的区别?

在世界上所有的差异。该defer语句返回后执行!这使您可以完成的事情,可以在没有其他办法来实现。

例如,你可以返回一个值,然后更改值。苹果利用这一招相当有规律;这里,例如,是从示出了如何编写自定义序列的序列文档代码:

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,然后返回它,我们要返回count,然后递减它。

此外,由于已经被指出的那样,defer语句无论你怎么退出执行。和它的作品无论你退出当前范围,这可能不涉及return可言; defer适用于函数体中,而块,如果构建一个DO块,等等。单return不退出这样一个范围内的唯一途径!有可能是你的方法不止一个return,和/或你可能会抛出一个错误,和/或你可能有一个break,等等,等等,或者你可能只是达到自然范围的最后一行;该defer在一切可能的情况下执行。编写相同的代码“手动”,以涵盖所有可能的退出,可以很容易出错。


16
投票

在您的例子其实没有什么区别,但是请看看这个:

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)始终执行无论在哪个行的函数返回。


7
投票

defer语句用来执行离去最近正好范围之前执行一段代码。

例如:

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

这将打印第一行是:起点

第二线,将打印的是:结束

最后一行将打印为:结束延迟功能的执行。


4
投票

使用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他们。如果函数从中间返回,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的代码,而另一方面,让你写的清理代码,不会初始化代码的旁边。

© www.soinside.com 2019 - 2024. All rights reserved.