在 Swift 语言中,逃逸闭包与非逃逸闭包的主要差异体现在哪些方面?请阐述二者的定义、使用场景以及编译器处理上的不同。
考察说明
考查 Swift 闭包基础概念中逃逸与非逃逸的核心区别及影响。
回答思路
- 【回答框架 1】非逃逸闭包是函数执行完毕前被调用的闭包,默认情况下闭包参数为非逃逸,编译器可优化其生命周期,无需捕获 self 时显式标记。
- 【回答框架 2】逃逸闭包在函数返回后才被执行或存储,必须在参数类型前标注 @escaping,常用于异步操作、回调存储、GCD 或组合操作中,此时需要显式处理循环引用。
- 【回答框架 3】编译器对非逃逸闭包可进行上下文优化,减少堆分配;逃逸闭包则必需堆分配,可能带来额外开销。调用方式上,非逃逸闭包可直接内联,逃逸闭包则受存储和异步影响。
- 【回答框架 4】使用逃逸闭包时,若闭包体内引用 self,需考虑捕获列表以避免循环引用,如使用 weak 或 unowned;非逃逸闭包由于同步执行,通常不存在此类风险。
- 【回答框架 5】选择时根据闭包是否需要存活超出函数作用域决定:仅同步使用选非逃逸,异步或持久化存储选逃逸,需明确标注 @escaping 以符合语法要求。
- 【关键点 1】非逃逸闭包默认,逃逸闭包需显式 @escaping 标注。
- 【关键点 2】逃逸闭包用于异步回调或存储,非逃逸用于同步调用。
- 【关键点 3】逃逸闭包可能引发循环引用,需处理 self 捕获。
- 【关键点 4】编译器对非逃逸闭包优化更强,逃逸闭包有堆分配开销。
- 【易错点 1】误将无需延迟执行的闭包标记为 @escaping,造成不必要的性能开销。
- 【易错点 2】忽略 Swift 版本差异,早期版本中对 @escaping 的处理稍有不同。
- 【易错点 3】在逃逸闭包中直接使用 self 而不采用捕获列表,容易产生循环引用导致内存泄漏。