编程iOS开发者

描述Swift中defer的工作机制,以及需要注意的边界情况和特点?

用 Hintsage AI 助手通过面试

答案。

defer是Swift中的一个特殊结构,允许在函数的作用域(scope)退出之前执行特定的代码块,无论是通过常规返回(return)还是错误(throw)退出。使用defer适合于释放资源,撤销更改或完成操作。

工作特点:

  • 如果函数中有多个defer,它们将按相反的顺序执行(后进先出,即LIFO结构)。
  • defer在发生错误(throw)或从函数的任何返回时都会执行。
  • 在closure中,defer与closure的主体相关,而不是与closure的调用位置相关。

示例:

func testDefer() { print("begin") defer { print("first defer") } defer { print("second defer") } print("end") } // 输出: // begin // end // second defer // first defer

边界情况:

  • defer在出现时捕获变量的值:如果在defer closure中使用变量,defer执行时对它们的修改将会被看到。
  • 如果函数以fatalError结束,defer将不会被调用。

带陷阱的问题。

如果在函数内调用fatalError,所有的defer块是否都会被执行?

回答: 不,如果在函数中调用fatalError(或类似的不可控崩溃),所有通过defer延迟的块将不会执行。defer在应用程序崩溃的情况下不保证代码的调用。

示例:

func foo() { defer { print("Defer 1") } fatalError("Oops") defer { print("Defer 2") } } foo() // 不会输出任何内容,将导致崩溃

因不了解主题细节而导致的实际错误示例。


故事

在项目中使用defer关闭文件描述符。在出现错误时使用fatalError而不是正确的throw,导致打开的资源泄露,因为在崩溃时defer不会执行。


故事

在一个函数中有多个defer,其中一些依赖于局部变量的状态。开发者期望变量等于特定值,但在defer中,这个值被其他代码块改变了,导致在执行defer时使用了当前值而不是旧值,从而导致了错误的事务ID撤销。


故事

在嵌套的closure中写了defer块,以为它会在退出外部函数时执行。结果这个defer在退出closure时执行,而不是整个函数,资源被过早释放。