编程iOS/Swift开发者

Swift中的defer语句是什么?它的执行特点是什么,何时适用,并可能遇到哪些陷阱?

用 Hintsage AI 助手通过面试

回答。

问题的背景:

defer被引入到Swift中(受到Go、C#等的启发),以确保在发生错误、退出函数或从函数的不同点返回值时,资源能够被清理。

问题:

提早释放、遗忘清理资源(例如,关闭文件、日志记录、事务回滚)。有时人们混淆了执行顺序,错误地认为defer在声明时就会执行。

解决方案:

defer是一个特殊的代码块,它会延迟执行直到当前作用域(scope)的结束,通常是函数的结束。所有defer按逆序执行(LIFO)。这使得能够集中管理资源的清理、内存的释放或事务的回滚。

代码示例:

func processFile() { let file = File("/tmp/data.txt") file.open() defer { file.close() print("文件已关闭") } // 与文件的操作 print("读取数据…") }

关键特点:

  • 在任何退出scope时都会执行,即使发生错误或提前返回。
  • 多个defer按逆序执行。
  • 可以在任何作用域中使用,不仅仅是在函数中。

陷阱问题。

如果应用程序在退出函数之前崩溃(defer)中的代码会执行吗?

不,defer中的代码只在正常退出作用域时执行。如果应用程序崩溃(例如,fatal error),defer将不会执行。

可以在defer中使用return吗?

不可以。defer块不允许返回值或结束作用域,只允许指令。

defer可以用于修改在defer之前声明的变量吗?

可以,defer会捕获执行时当前栈的值。在defer之前声明的值可以被修改,并且在退出scope时会保留这些修改。

代码示例:

func example() -> Int { var result = 0 defer { result = 42 } return result // defer将执行,结果为42 }

常见错误及反模式

  • 错误地期望defer在声明后立即执行。
  • 在没有意义的作用域外使用defer。
  • 在defer中留下繁重的操作。

生活中的例子

负面案例

文件打开了,但只在函数的底部显式关闭,而在错误或提前退出函数时,文件保持打开状态。

优点:

  • 实现简单

缺点:

  • 在错误中未关闭文件
  • 资源泄漏

正面案例

在打开文件后立即使用defer来关闭文件。即使发生异常或从函数返回,文件也能得到保证关闭。

优点:

  • 安全,无泄漏
  • 干净且可预测的代码

缺点:

  • 对defer内可变资源需谨慎