What’s new in Swift
Swift & Data 进阶 32m

Swift 的新功能

What’s new in Swift

2026年6月10日

在 Apple 官方观看视频

一句话判断

这场 Session 最值得关注的一件事是:Swift 终于把所有权系统(Ownership System)全面铺开到非拷贝类型(Noncopyable Types),让底层性能优化从“语法实验”变成了真正能写进生产环境的利器,顺手还用 anyAppleOS 干掉了折磨大家十年的多端可用性样板代码。

这场 Session 讲了什么

过去几年 Swift 在并发(Concurrency)上花了大力气,导致日常写代码时积累了不少语法债务,比如冗长的 @available 检查和让人抓狂的模块命名冲突。这次 Swift 6.3 和 6.4 集中清理了这些技术债,引入了 anyAppleOS、双冒号模块选择器(Module Selectors)和 @diagnose 属性,让日常开发体验顺畅了不少。

剥开这些语法糖的外衣,真正的重头戏是所有权系统(Ownership System)的成熟。非拷贝类型(Noncopyable Types)现在支持了 EquatableHashable 等基础协议,新增了 Iterable 协议和 borrow/mutate 访问器,标准库还补齐了 UniqueBoxRef 类型。这意味着你不再需要为了极致性能去写一堆 unsafe 代码,编译器现在能帮你安全地管理内存生命周期。

这对每天和 UI 打交道的业务开发者来说,可能只是少写了几个 #if os;但对于做音视频、引擎或者底层基础设施的团队,这波更新直接拔高了 Swift 在极致性能场景下的上限,让你能放心地把 C++ 模块用纯 Swift 重写。

值得深挖的点

anyAppleOS:: 模块选择器:干掉样板代码与命名冲突

Apple 终于意识到,让开发者在 @available 里把 iOS、macOS、watchOS、tvOS、visionOS 抄一遍是反人类的。anyAppleOS 的出现直接把多端可用性检查(Availability)的代码量砍掉了 80%。配合 #if os(anyAppleOS),跨平台代码的清理变得极其清爽。这不仅是少敲键盘的事,更是减少了漏写某个平台导致的线上 Crash。

让人抓狂的模块命名冲突也终于有了解法。以前如果两个模块有同名类型,用 Module.Type 经常会因为类型名和模块名同名而解析失败。Swift 6.3 引入的双冒号语法(Module::Type)直接告诉编译器“左边绝对是模块名”。这个设计非常克制,没有引入全新的命名空间概念,而是用最小的语法代价解决了 C++ 开发者转 Swift 时最怀念的特性之一。

所有权系统(Ownership System)走向完全体

去年引入的非拷贝类型(Noncopyable Types,即 ~Copyable)虽然惊艳,但因为不支持标准库的基础协议,在实际项目中很难用起来。今年 Apple 补全了这块拼图:EquatableComparableHashable 全面支持非拷贝类型。

更关键的是新增了 Iterable 协议和 borrow/mutate 访问器。以前遍历非拷贝集合会导致元素被消耗或拷贝,现在基于 borrow 的 for 循环可以做到零成本遍历。配合标准库新增的 UniqueBoxUniqueArrayRef 类型,Swift 终于有了一套完整的、类似 Rust 的智能指针和引用语义工具链。Trade-off 在于,这套心智模型对习惯了 ARC 自动管理的 iOS 开发者来说门槛较高,但如果你需要压榨最后 10% 的性能,这是目前唯一且安全的官方解法。

代码片段

1. 用 anyAppleOS 告别冗长的平台判断

场景:为 Apple 全平台写一个通用的 API 适配层。

extension Mission {
    // 以前需要写一长串 macOS, iOS, watchOS...
    // 现在一个 anyAppleOS 搞定所有 Apple 平台
    @available(anyAppleOS 27, *)
    func showStatus() { ... }

    // 如果某个平台不支持,单独排除即可
    @available(anyAppleOS 27, *)
    @available(tvOS, unavailable)
    func launch() { ... }
  
    // 编译期条件判断也支持了
    #if os(anyAppleOS)
    func makeLiveActivityWidget() -> some Widget { ... }
    #endif
}

坑:anyAppleOS 只包含 Apple 官方平台,如果你在做 Linux 或 Windows 的跨平台 Swift 服务端,这个属性对你无效,别乱用。

2. 用 :: 解决模块与类型同名冲突

场景:引入了第三方库,发现里面的类型名和模块名撞车了。

import Rocket
import GiftShopToys

// 报错:编译器不知道你想要哪个 SaturnV
// let rocket1 = SaturnV() 

// 坑:如果 Rocket 模块里刚好有个类叫 Rocket,点语法会失效
// let rocket2 = Rocket.SaturnV() // 编译器会去找 Rocket 类里的 SaturnV 成员

// 正确做法:用双冒号强制指定左侧为模块名
let rocket3 = Rocket::SaturnV() 

坑:双冒号语法目前只用于消除歧义,不要为了“看着像 C++”而在没有冲突的地方滥用,会被代码审查(Code Review)打回。

3. 用 @diagnose 精准控制警告

场景:重构老代码时,暂时屏蔽特定函数的废弃警告,或者在关键安全模块强制开启严格检查。

// 忽略特定函数的废弃警告,并留下重构备注
@diagnose(DeprecatedDeclaration, as: ignored, reason: "下个迭代替换为新引擎")
func makeApolloSoyuzMission() -> Mission {
    // 调用已废弃的 API 不会报警告
    CrewedMission(rocket: makeSaturnIRocket())
}

// 在涉及内存操作的关键函数中,把严格内存安全警告提升为 error
@diagnose(StrictMemorySafety, as: error)
func uplinkCommand(from receiver: inout Receiver) {
    // 这里的 unsafe 操作如果违规,直接编译失败
}

坑:@diagnose 的作用域仅限于它修饰的声明(函数/类),不会污染整个文件,所以别指望加在文件头就能全局生效。

最佳实践

对于已有项目,立刻全局搜索 @available(iOS *, macOS *, *) 并替换为 anyAppleOS,这能瞬间让你的代码库清爽不少。同时,排查项目中因为模块命名冲突而使用的奇怪别名(typealias),用 :: 语法还原它们真实的命名。

对于新项目或性能敏感模块,强烈建议尝试非拷贝类型(Noncopyable Types)。从标准库的 UniqueBoxRef 开始,理解 borrowconsume 的语义。不要一开始就试图把整个数据模型改成 ~Copyable,先在文件句柄、数据库连接、锁(Lock)这种“独占资源”上使用,体会编译器如何帮你防止资源泄漏和重复释放。

实战中最容易踩的坑是 weak let。虽然它解决了 weak var 导致类无法自动推断为 Sendable 的问题,但 weak let 意味着引用不可变,你只能在初始化时赋值一次。如果你的设计模式依赖后续重新绑定弱引用,这个特性并不适合你。

还有什么值得关注

  • Subprocess 1.0 正式发布:做服务端或命令行工具的开发者有福了,新的 API 支持逐行流式输出(line-by-line output streaming),不用再自己封装难用的 Pipe 了。
  • Swift Testing 增强:支持了动态取消测试和 Flaky test(不稳定测试)自动重试,终于不用为了偶发的网络超时去写恶心的 XCTWaiter 重试逻辑了。
  • WebAssembly 与 JavascriptKit 提速:Swift 编译到 Wasm 的桥梁性能提升了 40 倍,用 Swift 写前端高性能计算模块(比如图像处理、加密)现在真正具备商业可行性了。
Swift 6.4 Noncopyable Types anyAppleOS Module Selectors Ownership System