【问题标题】:Different Behaviour of defer statementdefer 语句的不同行为
【发布时间】:2019-06-06 14:48:46
【问题描述】:

我在注销按钮上有代码,我正在使用defer 语句。

我想知道在操作方法范围内更改 defer 语句代码的位置时。

  1. 我在方法末尾添加了defer 语句,它向我显示警告。

作用域结束前的'defer'语句总是立即执行; 替换为 'do' 语句以消除此警告

代码:

override func sendButtonTapped(sender: Any) {

    self.deleteCoreData()
    self.clearUserDefaults()

    // Clear view context
    AppDelegate.shared.persistentContainer.viewContext.reset()

    ....
    ....

    // Call after all code execution completed in this block's Scope
    defer {
        // Set isUserLoggedIn and change root view controller.
        UserDefaults.Account.set(false, forKey: .isUserLoggedIn)
        AppDelegate.shared.setRootViewController()
    }
}
  1. 然后,我在方法的开头添加了defer 语句,它什么都不显示。

代码:

override func sendButtonTapped(sender: Any) {

    // Call after all code execution completed in this block's Scope
    defer {
        // Set isUserLoggedIn and change root view controller.
        UserDefaults.Account.set(false, forKey: .isUserLoggedIn)
        AppDelegate.shared.setRootViewController()
    }

    self.deleteCoreData()
    self.clearUserDefaults()

    // Clear view context
    AppDelegate.shared.persistentContainer.viewContext.reset()

    ....
    ....
}

谁能解释一下defer 语句到底发生了什么?

【问题讨论】:

  • 把它放在函数的末尾是没有意义的,它只是在 defer 里面移动代码,为什么?
  • 您好 Mayur,延迟的行为发生了变化。之前: defer 在函数返回后执行他的代码。示例:返回 1; defer.. 而不是这种行为 defer 现在在函数 return(exit) 之前执行。示例:推迟..返回。所以编译器只是说把你的代码放在延迟中是没有意义的。
  • 也就是说,如果我将代码放在defer 中,那么它会在defer 之外的代码之前执行?
  • 不,defer 总是在函数结束之前、return 之前执行,或者如果没有“return”,则在函数中执行最新代码
  • 不用说,defer 的主要优点之一是它确保无论您如何退出当前范围(即,如果您有任何提前退出 @ 987654331@ 声明,或者你有什么)。如果您的代码中没有任何return 语句,那么defer 语句几乎没有什么好处。

标签: ios swift


【解决方案1】:

综上所述,defer 语句将在你所在的作用域的末尾执行。(.apple doc : https://docs.swift.org/swift-book/ReferenceManual/Statements.html#grammar_defer-statement

来自苹果文档

func f() {
    defer { print("First defer") }
    defer { print("Second defer") }
    print("End of function")
}
f()
// Prints "End of function"
// Prints "Second defer"
// Prints "First defer"

defer 语句允许您定义将在您想要完成的其余操作之后执行的操作,即在 范围 的末尾>。

警告也非常明确,考虑到您将 defer 语句放在范围的末尾,它没有任何用途:

func f() {
    print("TIC")
    defer { print("TAC") } // will be print at the end of the function
}
f()
// Prints "TIC"
// Prints "TAC""

这与:

func f() {
    print("TIC")
    print("TAC") // no defer, same result
}
f()
// Prints "TIC"
// Prints "TAC""

走得更远

那么为什么警告会建议您使用do 块? 其实前面两个例子并不是100%一样,当你使用defer语句时,它会创建自己的scope

func f() {
    // here you are in the scope of the `f()` function
    print("TIC")
    defer { 
        // here you are the scope of the `defer` statement
        print("First defer") 
    }
}

最接近手动创建作用域的方法是do 语句

func f() {
    // here you are in the scope of the `f()` function
    print("TIC")
    do { 
        // here you are the scope of the `do` statement
        print("First defer") 
    }
}

来自苹果文档

do 语句用于引入新的作用域,并且可以选择包含一个或多个 catch 子句,其中包含与定义的错误条件匹配的模式。在 do 语句范围内声明的变量和常量只能在该范围内访问。

如果你想了解更多关于作用域的知识,这里有一些讲座:https://andybargh.com/lifetime-scope-and-namespaces-in-swift/

本质上,对象作用域定义了我们程序中可以访问项目的区域。

【讨论】:

    【解决方案2】:

    根据 Swift 文档:

    defer 语句用于在将程序控制转移到 defer 语句出现的范围之外之前执行代码。这意味着可以使用 defer 语句,例如,执行手动资源管理 例如关闭文件描述符,并执行即使抛出错误也需要执行的操作

    在您的示例中,在代码末尾使用defer 是没有用的,因为代码将以与defer 外部完全相同的方式执行,因为defer 只执行代码在退出当前范围(方法)之前。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-04
      • 2011-07-29
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 2012-05-03
      相关资源
      最近更新 更多