延迟声明的不同行为

时间:2019-06-06 06:34:23

标签: ios swift

我在使用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语句到底发生了什么吗?

2 个答案:

答案 0 :(得分:2)

总结起来,defer语句将在您所在的作用域的末尾执行。(.apple doc:https://docs.swift.org/swift-book/ReferenceManual/Statements.html#grammar_defer-statement

来自Apple文档

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语句,您可以定义要在要完成的其余操作之后 之后执行的操作,即在作用域的结尾< / strong>。

考虑到您将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") 
    }
}

来自Apple文档

  

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

如果您想了解有关范围的更多信息,这里有一些讲座:https://andybargh.com/lifetime-scope-and-namespaces-in-swift/

  

从本质上讲,对象范围定义了程序中可以访问该项目的区域。

答案 1 :(得分:1)

根据Swift文档:

  

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

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