Swift 中重要特性——逃逸闭包@escaping

@escaping 是 Swift 中一个非常重要的特性,通常用于闭包(closure)的参数,尤其是在处理异步操作或回调时。它用于标记闭包参数"逃逸"出了函数的作用域,即闭包的生命周期超出了函数的执行范围。

为什么需要 @escaping

在 Swift 中,闭包默认是非逃逸(non-escaping)的,也就是说,闭包只能在函数调用过程中执行,并且不会保存到外部的变量或常量中。这样做的目的是提高性能,因为闭包不需要被保持,编译器可以进行优化。

然而,在处理异步操作时,比如网络请求或定时器,我们需要将闭包传递出去,让它在函数执行完毕后(甚至在函数退出后)继续执行。这时,闭包需要逃逸 出函数的作用域,这时就需要使用 @escaping 来显式标记这个闭包参数。

@escaping 的作用

@escaping 表示闭包会逃逸出函数的作用域,可以在函数返回后被执行。这通常用于处理异步回调或者其他延迟执行的场景。

关键点

  • 非逃逸闭包(non-escaping closure):闭包只能在函数内部执行,并且会在函数返回前执行完毕。默认情况下,函数的闭包参数是非逃逸的。
  • 逃逸闭包(escaping closure):闭包可以在函数返回之后仍然执行,通常用于异步回调。

例子:非逃逸闭包

如果没有使用 @escaping,闭包是非逃逸的,不能存储到函数外部。

swift 复制代码
func performTask(task: () -> Void) {
    task()  // 这里闭包被执行并且在函数内完成
}

例子:逃逸闭包

当闭包需要在函数执行完毕后仍然执行,通常会标记为 @escaping。最典型的例子是异步操作,例如网络请求或定时器。

swift 复制代码
func fetchData(completion: @escaping (Data?) -> Void) {
    DispatchQueue.global().async {
        // 模拟网络请求
        let data = Data()
        completion(data)  // 闭包会在函数返回后执行
    }
}

在上面的例子中,completion 闭包会逃逸出 fetchData 函数,因为它是在一个异步线程中执行的,函数返回后闭包才会被调用。

逃逸闭包与内存管理

由于逃逸闭包的生命周期可能超过函数的执行时间,它可能会导致内存管理问题。逃逸闭包会被持有到函数执行完成后,因此需要特别小心避免强引用循环(retain cycles)。

通常,为了避免强引用循环,我们会将闭包声明为 weakunowned,从而防止闭包持有对象的强引用。

使用 weakunowned 避免循环引用

swift 复制代码
func fetchData(completion: @escaping (Data?) -> Void) {
    DispatchQueue.global().async { [weak self] in
        // 使用 weak 或 unowned 防止循环引用
        guard let self = self else { return }
        let data = Data()
        completion(data)
    }
}

使用 @escaping 的实际场景

@escaping 主要用于异步操作或回调函数,它的作用是使闭包可以在函数执行完毕后,甚至在函数返回后继续执行。

  1. 网络请求回调:在网络请求成功或失败后执行回调操作。
  2. 定时器回调:在定时器触发时执行闭包操作。
  3. UI 更新回调:例如,在多线程中更新 UI,闭包可能需要在主线程执行。

总结

  • @escaping 标记闭包为逃逸闭包,即它可能在函数返回后被调用。
  • 逃逸闭包通常用于处理异步操作、回调等情况。
  • 逃逸闭包的生命周期可能会超过函数的作用域,因此需要注意内存管理,避免出现强引用循环。
相关推荐
SoaringHeart11 分钟前
Flutter最佳实践:IM聊天文字链接自动识别跳转
前端·flutter
掘金一周1 小时前
企业中要做智能体,最佳的方案是什么? | 沸点周刊 6.18
前端·人工智能·ai编程
Darling噜啦啦1 小时前
CSS 3D 变换与 Flex 布局实战:从零打造旋转立方体
前端·css
秃头网友小李1 小时前
前端难点:keep-alive 缓存什么?RouterView 的 key 为什么要带 scopeId?
前端·vue.js
鱼人1 小时前
CSS 变量:一个变量救你一百次复制粘贴
前端
长大19881 小时前
CSS 到底是什么?和 HTML 的区别一次讲清楚
前端
禅思院1 小时前
路由性能优化终极指南:从懒加载漏洞到边缘渲染的架构跃迁
前端·架构·前端框架
怕浪猫1 小时前
Electron 开发实战(十六):总结与展望|生态现状、框架对比、行业趋势与学习指南
前端·javascript·electron
文心快码BaiduComate1 小时前
Comate 搭载GLM-5.2:百万上下文,稳定支撑长程任务
前端·程序员·开源
星栈2 小时前
Dioxus 的 `rsx!` 语法:如果你会 React,上手确实特别快
前端·前端框架