首页 > 解决方案 > defer 语句的不同行为

问题描述

我在注销按钮上有代码,我正在使用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语句到底发生了什么?

标签: iosswift

解决方案


总而言之,该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语句时,它会创建自己的作用域

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/

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


推荐阅读