What's new in Swift
Developer Tools 进阶 0m

Swift 6.2 新特性全览

What's new in Swift

2025年6月9日

在 Apple 官方观看视频

一句话判断

Swift 6.2 的核心主题是”并发退一步、性能进一步”——默认单线程、按需并发的策略让 data-race safety 不再是初学者的噩梦。

这场 Session 讲了什么

Swift 6.2 是一次覆盖面极广的更新,从语言特性到工具链到生态系统都有实质性进展。语言层面最重大的变化是并发模型的哲学转向:从”默认并发、编译器帮你排雷”变成了”默认单线程、你主动选择并发”。具体来说,async 函数默认不再脱离当前 actor 执行,@MainActor 可以作为全局默认推断模式开启,isolated conformance 让 main actor 类型也能安全实现协议。

性能方面,InlineArray 作为固定大小数组类型正式登场,元素直接内联存储在栈上,避免了 Array 的堆分配和引用计数开销。配合 Span 类型提供对连续内存的安全零拷贝访问,编译时保证生命周期安全,消除了 unsafe pointer 的常见陷阱。

工具链方面,swiftly 1.0 正式发布并支持 macOS,Xcode 的 Swift extension for VS Code 获得后台索引和 DocC 预览。build 系统方面,pre-built swift-syntax 依赖彻底消除了 macro 项目的 clean build 瓶颈,Explicitly Built Modules 让 debugger 首次执行 p/po 命令时不再等待模块构建。

生态系统层面,Swift 正式支持 FreeBSD 和 WebAssembly,Embedded Swift 扩展了完整 string API,strict-memory-safety 模式要求显式标记所有 unsafe API 调用。gRPC Swift v2 发布,swift-java 互操作项目持续演进,Apple 内部用 Swift 重写的密码泄露检测服务吞吐量提升 40%、硬件需求减半。

值得深挖的点

默认单线程:并发模型的哲学大转弯

Swift 6.0 引入的 data-race safety 是个正确的方向,但实践中很多开发者被编译器的并发错误搞得焦头烂额——不是因为他们真的在写并发代码,而是语言在很多”隐式”的地方把工作 offload 到了后台线程。一个带有 mutable state 的 class,调用它的 async 方法就可能触发 data-race error,即使你根本没想要并行执行。

Swift 6.2 彻底反转了这个优先级:代码默认保持在当前 actor 上执行,除非你显式标记 @concurrent。这意味着你写一个 PhotoProcessor 类的 async 方法,调用方在 main actor 上调用它,整个执行流不会离开 main actor,不存在 data race 的可能。

这个 trade-off 很明确:默认安全性大幅提升,但如果你需要后台执行 CPU 密集型任务,必须用 @concurrent 显式标记。好处是代码意图更清晰——看到 @concurrent 就知道这里是有意并行,而不是语言的隐式行为。对于大部分 app 开发场景(特别是 UIKit/SwiftUI app),这大幅降低了并发编程的入门门槛。

@MainActor 默认推断模式进一步简化了单线程 app 的代码。开启后,全局变量、静态变量、SDK 中的 main actor API 调用都不会再产生 data-race 警告。这个模式推荐给 app target、script 等可执行目标,但不推荐给 library——library 需要保持对不同 actor 使用场景的兼容性。

InlineArray 和 Span:性能敏感代码的新武器

Array 的灵活性来自堆分配的 buffer 和动态扩容能力,但这些特性在性能关键路径上成了负担。InlineArray<3, Int> 的元素直接存储在变量所在的位置(栈上或 struct 内部),没有堆分配、没有引用计数。编译器知道大小是 3,可以在编译期消除某些边界检查。

但固定大小意味着你必须在编译期知道元素数量。这不适合动态增长的场景,但非常适合 shader 参数、固定格式解析、嵌入式设备的缓冲区等场景。类型参数里的整数(<3, Int>)是一个新的 generics 能力,不仅限于 InlineArray

Span 提供对 Array、InlineArray 等容器底层连续内存的安全访问。关键在于编译时的生命周期依赖:修改原始容器后,之前获取的 span 自动失效,不能再次访问。这用编译时检查杜绝了 use-after-free 和 overlapping modification,零运行时开销。相比 unsafe pointer,这是质的提升——你获得了同样的性能,但不需要手动保证内存安全。

代码片段

1. @concurrent 显式后台执行

场景:在 main actor 默认模式下,标记 CPU 密集型任务在后台线程执行。

@concurrent
func extractSubject(from imageData: Data) async throws -> Sticker {
    // 这个函数始终在线程池上执行,不阻塞 main actor
    let cgImage = try await heavyImageProcessing(imageData)
    return Sticker(image: cgImage)
}

坑:@concurrent 函数不能直接访问 main actor 的 mutable state,调用方需要确保传入的参数是可跨 actor 安全传递的值类型或 Sendable 类型。

2. InlineArray 基础用法

场景:用固定大小数组存储 shader uniform 参数,避免堆分配。

var kernelWeights: InlineArray<9, Float> = [
    1, 2, 1,
    2, 4, 2,
    1, 2, 1
]

// 大小可从字面量推断
let offsets: InlineArray = [(-1, -1), (0, -1), (1, -1)]

坑:InlineArray 的大小是类型的一部分,不能在运行时改变。如果需要动态大小,还是得用 Array

3. Span 安全访问容器内存

场景:将 Array 的底层内存传递给高性能处理函数,无需拷贝。

func processBuffer(_ buffer: inout [Float]) {
    let span = buffer.span
    // 直接操作连续内存,零拷贝
    for i in span.indices {
        // 读取 span[i]
    }
    // 修改 buffer 后,span 自动失效,不能再访问
    buffer.append(1.0)
    // 下面这行会编译错误:
    // let x = span[0]  // span lifetime 已被 invalidation
}

坑:Span 的生命周期依赖是编译时检查,但如果你在 span 存活期间通过其他引用修改了底层容器,编译器会报错。这是有意的安全设计,不是 bug。

最佳实践

  • 新项目在 Xcode build settings 中开启 @MainActor 默认推断模式,大幅减少并发标注噪音。
  • 对 CPU 密集型的 async 函数显式添加 @concurrent,让意图清晰、性能可预期。
  • 性能关键路径上的固定大小数据用 InlineArray 替代 Array,消除不必要的堆分配。
  • 需要零拷贝访问容器内存时,优先使用 Span 而非 unsafe pointer。
  • 在 SwiftPM manifest 中使用 SwiftSettings API 开启新的 concurrency 特性,不要手动修改每个文件。
  • 使用 swiftly 1.0 管理多版本 toolchain,CI 环境特别受益。

还有什么值得关注

  • swiftlang GitHub 组织已扩展到 50+ 个项目,Xcode 的 build system Swift Build 也已开源,正在被集成到 SwiftPM 中。
  • Swift Testing 新增 custom attachment(Attachment.record)和 exit test(#expect(processExitsWith:)),让 CI 上的失败更容易诊断。
  • Foundation 新增 Subprocess package,用 Swift 写脚本不再需要 Process 的繁琐配置,API 设计更现代。
开发工具 Swift