Swift 闭包:从基础语法到实战进阶
1. 什么是闭包闭包是 Swift 中一种自包含的函数代码块它可以捕获并存储其所在上下文中的常量和变量。简单来说闭包就是可以像普通函数一样被调用、可以赋值给变量、可以作为参数传递的代码块。在 Swift 中全局函数和嵌套函数本质上也是闭包的一种特殊形式。闭包有三种形式全局函数有名字但不会捕获任何值的闭包。嵌套函数有名字且可以捕获其所在函数体内值的闭包。闭包表达式轻量级语法可以捕获其所在上下文中值的匿名闭包。2. 闭包基础语法闭包表达式的基本语法格式如下{ (参数列表) - 返回类型 in 函数体代码 }下面通过一个简单的排序示例来理解闭包的基本用法。Swift 标准库中的sorted(by:)方法接收一个闭包作为参数用于定义排序规则let names [Chris, Alex, Ewa, Barry, Daniella] // 使用普通函数作为排序规则 func backward(_ s1: String, _ s2: String) - Bool { return s1 s2 } var reversedNames names.sorted(by: backward) // 使用闭包表达式 reversedNames names.sorted(by: { (s1: String, s2: String) - Bool in return s1 s2 })上面的闭包表达式完整地写出了参数类型和返回类型但 Swift 提供了多种简化写法让代码更加简洁。3. 闭包语法简化3.1 根据上下文推断类型因为sorted(by:)方法的参数类型是已知的Swift 可以推断出闭包的参数类型和返回类型因此可以省略类型声明reversedNames names.sorted(by: { s1, s2 in return s1 s2 })3.2 单表达式隐式返回如果闭包体只有一行表达式可以省略return关键字reversedNames names.sorted(by: { s1, s2 in s1 s2 })3.3 简写参数名Swift 自动为闭包提供简写参数名$0、$1、$2等可以省略参数列表和in关键字reversedNames names.sorted(by: { $0 $1 })3.4 运算符方法对于字符串比较这种场景可以直接传入运算符函数因为本身就是一个接收两个参数并返回 Bool 的函数reversedNames names.sorted(by: )4. 尾随闭包当闭包是函数的最后一个参数时可以将闭包写在函数调用的括号之外这种写法称为尾随闭包。它让代码在函数较长时更加易读// 不使用尾随闭包 reversedNames names.sorted(by: { $0 $1 }) // 使用尾随闭包 reversedNames names.sorted() { $0 $1 } // 如果闭包是唯一参数可以省略函数调用的括号 reversedNames names.sorted { $0 $1 }尾随闭包在 SwiftUI 中非常常见例如按钮的点击事件处理Button(点击我) { print(按钮被点击了) }5. 捕获值闭包可以在其函数体内捕获并存储所在上下文中定义的常量和变量。即使这些常量和变量的原始作用域已经不存在闭包仍然可以在其函数体内引用和修改它们。func makeIncrementer(forIncrement amount: Int) - () - Int { var runningTotal 0 func incrementer() - Int { runningTotal amount return runningTotal } return incrementer } let incrementByTen makeIncrementer(forIncrement: 10) print(incrementByTen()) // 输出 10 print(incrementByTen()) // 输出 20 print(incrementByTen()) // 输出 30上面的示例中嵌套函数incrementer捕获了runningTotal和amount两个变量。每次调用incrementByTen时runningTotal都会在上一次的基础上继续累加。需要注意的是如果闭包捕获的是变量它可以在闭包内部修改该变量的值如果捕获的是常量则只能读取不能修改。6. 闭包是引用类型在 Swift 中函数和闭包都是引用类型。当你把一个闭包赋值给另一个变量时实际上是将同一个闭包的引用赋值过去两个变量指向同一个闭包let incrementByTen makeIncrementer(forIncrement: 10) let alsoIncrementByTen incrementByTen print(incrementByTen()) // 输出 10 print(alsoIncrementByTen()) // 输出 20两个变量共享同一个闭包7. 逃逸闭包与非逃逸闭包7.1 非逃逸闭包默认情况下闭包是非逃逸的。非逃逸闭包在函数返回之前就会被调用不会在函数返回后继续存在。由于不需要考虑生命周期问题非逃逸闭包在使用时更加高效func performOperation(_ operation: () - Void) { // 闭包在函数体内被调用 operation() } performOperation { print(这是一个非逃逸闭包) }7.2 逃逸闭包当闭包需要在函数返回之后才被调用时需要在参数类型前加上escaping关键字将其标记为逃逸闭包。最常见的场景是异步网络请求var completionHandlers: [() - Void] [] func downloadData(completion: escaping () - Void) { // 将闭包存储到数组中函数返回后闭包仍然存在 completionHandlers.append(completion) // 模拟异步操作 DispatchQueue.global().async { // 模拟网络请求耗时 sleep(2) // 在异步任务完成后调用闭包 completion() } } downloadData { print(数据下载完成) }逃逸闭包需要注意循环引用问题。如果闭包内部捕获了self而self又持有该闭包就会形成循环引用导致内存泄漏。此时需要使用[weak self]或[unowned self]来打破循环class DataLoader { var data: String func loadData() { downloadData { [weak self] in guard let self self else { return } self.data 加载完成 print(self.data) } } }8. 自动闭包自动闭包是一种自动创建的闭包用于包装传递给函数作为参数的表达式。自动闭包不接受任何参数当它被调用时会返回包装在其中的表达式的值。使用autoclosure关键字来标记func logIfTrue(_ condition: autoclosure () - Bool) { if condition() { print(条件为真) } } // 调用时不需要写花括号直接传入表达式 logIfTrue(2 1) // 输出 条件为真自动闭包的一个典型应用是 Swift 中的assert函数。它只在调试模式下执行并且只有在条件为假时才计算表达式从而避免不必要的性能开销。9. 实战案例使用闭包实现回调下面通过一个完整的示例来展示闭包在真实项目中的应用。假设我们要实现一个简单的网络请求工具类import Foundation struct User { let id: Int let name: String } enum NetworkError: Error { case invalidResponse case serverError(code: Int) } class APIClient { // 使用逃逸闭包处理异步回调 func fetchUser(id: Int, completion: escaping (ResultUser, Error) - Void) { // 模拟网络请求 DispatchQueue.global().asyncAfter(deadline: .now() 1) { // 模拟请求成功 let user User(id: id, name: 用户\(id)) completion(.success(user)) // 模拟请求失败 // completion(.failure(NetworkError.serverError(code: 500))) } } } // 使用示例 let client APIClient() client.fetchUser(id: 1001) { result in switch result { case .success(let user): print(获取用户成功\(user.name)) case .failure(let error): print(获取用户失败\(error.localizedDescription)) } }10. 实战案例高阶函数与闭包Swift 的数组提供了map、filter、reduce等高阶函数它们都接收闭包作为参数是闭包最广泛的应用场景之一。let numbers [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // map对每个元素进行转换 let squaredNumbers numbers.map { $0 * $0 } print(squaredNumbers) // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] // filter筛选符合条件的元素 let evenNumbers numbers.filter { $0 % 2 0 } print(evenNumbers) // [2, 4, 6, 8, 10] // reduce将所有元素合并为一个值 let sum numbers.reduce(0) { $0 $1 } print(sum) // 55 // 链式调用 let result numbers .filter { $0 % 2 0 } .map { $0 * $0 } .reduce(0, ) print(result) // 22011. 总结闭包是 Swift 中非常强大且灵活的特性掌握闭包是写出简洁、优雅 Swift 代码的关键。本文从闭包的基础语法出发逐步介绍了语法简化、尾随闭包、值捕获、逃逸闭包和自动闭包等核心概念并通过实战案例展示了闭包在异步回调和函数式编程中的典型应用。在实际开发中建议多使用闭包的简化写法来提升代码可读性同时注意逃逸闭包中的循环引用问题合理使用[weak self]来避免内存泄漏。

相关新闻

Swift 变量详解:从基础到实战

Swift 变量详解:从基础到实战

1. 引言变量是 Swift 编程中最基础也最重要的概念之一。无论是存储用户输入、计算结果还是管理应用状态,都离不开变量的使用。本文将从变量的声明方式、命名规范、类型推断到实际应用场景,结合丰富的代码实例,帮助你全面掌握 Swift 变量。2. …

2026/10/18 7:08:10 阅读更多 →
智能体记忆系统设计:从向量数据库到个性化助手的工程实践

智能体记忆系统设计:从向量数据库到个性化助手的工程实践

1. 项目概述:从“金鱼脑”到“过目不忘”的智能体进化 在智能体(Agent)的开发与应用中,我们常常会遇到一个令人头疼的瓶颈:智能体表现得像个“金鱼”,对话一结束,上下文就清零,下次互…

2026/10/19 0:23:49 阅读更多 →
Unity Tile Palette 2D地图编辑:从基础绘制到Rule Tile智能生成

Unity Tile Palette 2D地图编辑:从基础绘制到Rule Tile智能生成

1. 从“手绘”到“拼图”:为什么我们需要瓦片调色板 如果你是从零开始接触Unity 2D游戏开发,或者是从其他引擎(比如GameMaker、Godot)转过来的,你可能会对Unity的2D工作流感到一丝困惑。尤其是在处理关卡、地图这些需要…

2026/10/18 7:08:11 阅读更多 →

最新新闻

Upscayl 本地 AI 图像放大:装完点 3 下按钮搞定一张 4 倍放大图

Upscayl 本地 AI 图像放大:装完点 3 下按钮搞定一张 4 倍放大图

Upscayl 本地 AI 图像放大:装完点 3 下按钮搞定一张 4 倍放大图 【免费下载链接】upscayl 🆙 Upscayl - #1 Free and Open Source AI Image Upscaler for Linux, MacOS and Windows. 项目地址: https://gitcode.com/GitHub_Trending/up/upscayl U…

2026/10/19 1:13:15 阅读更多 →
WeKnora 本地部署指南:30 分钟跑起你自己的 RAG 知识库

WeKnora 本地部署指南:30 分钟跑起你自己的 RAG 知识库

WeKnora 本地部署指南:30 分钟跑起你自己的 RAG 知识库 【免费下载链接】WeKnora Open-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki. 项目地址: https://gitcode.com/…

2026/10/19 1:13:15 阅读更多 →
电大计算机专业毕业论文全流程指南:选题、查重、格式与答辩

电大计算机专业毕业论文全流程指南:选题、查重、格式与答辩

简介:面向电大计算机科学与技术专业学生的毕业论文,主题为图书信息管理系统的设计与实现。论文完整覆盖管理信息系统建设的关键环节,从需求分析、功能模块划分,到数据库结构设计和前端应用程序开发均有详细介绍。系统采用易语言开…

2026/10/19 1:13:15 阅读更多 →
粒子群算法优化极限学习机:从随机初始化到参数寻优

粒子群算法优化极限学习机:从随机初始化到参数寻优

简介:面向Matlab数据分类任务,压缩包提供基于粒子群优化的极限学习机(PSO-ELM)完整实现,借助PSO对ELM输入权值与隐含层阈值进行寻优,适合需要提升分类精度、开展算法对比或复现论文实验的科研人员、研究生与…

2026/10/19 1:13:15 阅读更多 →
ComfyUI LTXVideo 入门指南:3 条路径生成 AI 视频

ComfyUI LTXVideo 入门指南:3 条路径生成 AI 视频

ComfyUI LTXVideo 入门指南:3 条路径生成 AI 视频 【免费下载链接】ComfyUI-LTXVideo LTX-Video Support for ComfyUI 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-LTXVideo ComfyUI LTXVideo 把 LTX-2 视频生成模型接入 ComfyUI,…

2026/10/19 1:13:15 阅读更多 →
STM32单片机 2引脚按键

STM32单片机 2引脚按键

按键:常见的输入设备,按下导通,松手断开按键抖动:由于按键内部使用的是机械式弹簧片来进行通断的,所以在按下和松手的瞬间会伴随有一连串的抖动为防止按键按一下,单片机却反应多次的现象,因此要…

2026/10/19 1:12:12 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →