defer操作符在Swift中引入,用于安全和保证资源的清理或在离开作用域时执行代码,类似于其他语言中的finally/using/RAII。
多步骤初始化、文件操作、跨场景的函数退出 — 需要保证资源的释放或逻辑的执行(关闭文件、解锁mutex,将对象返还到池中、重置临时状态)。在defer出现之前,所有这些都必须在每个return中手动执行。
defer保证在当前作用域退出时执行其代码,无论退出是正常的还是通过throw。可以声明多个defer,它们将按声明的逆序执行。
资源释放的示例:
func processFile(path: String) throws { let file = try openFile(path) defer { file.close() } // 在发生错误时也会确保调用 // ... 处理文件 ... }
关键特点:
defer能否捕获变量的引用,以及这对闭包的行为有什么影响?
是的,defer在调用时捕获所有使用的变量,按照闭包的捕获规则(值类型复制,引用类型引用)。捕获可变的外部值变量将导致错误——在执行defer时它可能已经改变。
在循环和函数内部嵌套defer是如何工作的?
如果defer在循环内部声明,则在每次迭代的作用域结束时执行:
for _ in 1...3 { defer { print("End of iteration") } print("Inside") }
将输出:
Inside
End of iteration
Inside
End of iteration
Inside
End of iteration
defer能否不被执行?
只有在实际离开作用域时才能保证执行defer的代码。但如果进程异常终止(fatalError、崩溃),或调用了exit,defer将不会执行。此外,defer不在对象方法级别工作 — 仅在函数/块的作用域内。
在打开文件并进行操作后,通过不同的return/throw进行返回,在一个地方忘记关闭文件。最终打开的文件句柄泄漏到系统中。
优点:
缺点:
使用defer来确保解锁mutex、释放文件描述符和重置进度标志:
func criticalSection() { lock() defer { unlock() } // ... 工作 ... }
优点:
缺点: