Swift 新特性
问题
Swift 5.5 到 Swift 6.0 有哪些重要的新特性?Macro、Strict Concurrency、Noncopyable 类型分别是什么?
答案
Swift 版本新特性一览
| 版本 | 核心特性 |
|---|---|
| 5.5 | async/await、Actor、Structured Concurrency |
| 5.7 | if let 简写、some/any 关键字、正则字面量 |
| 5.9 | Macro、Parameter Pack(变参泛型)、~Copyable |
| 5.10 | 全局 Actor 隔离改进、Strict Concurrency 检查默认警告 |
| 6.0 | Strict Concurrency 默认强制、Typed Throws、count(where:) |
Swift 5.7:if let 简写 & some/any
// if let 简写(shadowing)
let name: String? = "Alice"
if let name { // 不用写 if let name = name
print(name)
}
// 明确 some vs any
func draw(shape: some Shape) { } // 不透明类型,静态分发
func draw(shapes: [any Shape]) { } // 存在类型,异构集合
Swift 5.9:Macro
Macro 在编译时生成代码,减少样板代码:
// 使用 @Observable 宏(替代 ObservableObject + @Published)
@Observable
class UserViewModel {
var name = "Alice" // 自动追踪变化,无需 @Published
var age = 25
}
// 展开后自动生成 _name 存储 + willSet 通知代码
常见标准库 Macro:
| Macro | 用途 |
|---|---|
@Observable | 替代 ObservableObject(SwiftUI) |
#Preview | 替代 PreviewProvider |
#Predicate | 类型安全的谓词构建 |
@Model | SwiftData 模型声明 |
// #Preview 宏
#Preview("My View") {
ContentView()
}
// @Model 宏(SwiftData)
@Model
class Trip {
var name: String
var destination: String
var startDate: Date
}
Swift 5.9:Parameter Pack(变参泛型)
处理可变数量的泛型参数:
// 传统方式需要为 2、3、4... 个参数分别写重载
func zip<A, B>(_ a: A, _ b: B) -> (A, B) { (a, b) }
func zip<A, B, C>(_ a: A, _ b: B, _ c: C) -> (A, B, C) { (a, b, c) }
// Parameter Pack:一个函数搞定
func allEqual<each T: Equatable>(_ values: repeat each T, to others: repeat each T) -> Bool {
// ...
}
Swift 5.9:Noncopyable 类型(~Copyable)
禁止隐式复制的类型,用于资源管理:
struct FileHandle: ~Copyable {
private let fd: Int32
init(path: String) { fd = open(path, O_RDONLY) }
consuming func close() {
Darwin.close(fd)
}
deinit {
Darwin.close(fd)
}
}
var file = FileHandle(path: "/tmp/test")
// let copy = file // ❌ 编译错误:不可复制
file.close() // consuming:调用后 file 不再可用
Swift 6.0:Strict Concurrency
Swift 6 将数据竞争检查从警告升级为编译错误:
// Swift 6 模式下,以下代码编译错误
var counter = 0
Task {
counter += 1 // ❌ 错误:在并发上下文中修改非 Sendable 变量
}
// ✅ 正确做法
actor Counter {
var value = 0
func increment() { value += 1 }
}
Swift 6.0:Typed Throws
enum ValidationError: Error {
case tooShort, invalidCharacter
}
// 指定抛出的错误类型
func validate(_ input: String) throws(ValidationError) -> String {
guard input.count >= 3 else { throw .tooShort }
guard input.allSatisfy(\.isLetter) else { throw .invalidCharacter }
return input
}
do {
try validate("ab")
} catch {
// error 类型是 ValidationError(不是 any Error)
switch error {
case .tooShort: print("太短")
case .invalidCharacter: print("非法字符")
}
}
其他实用新特性
// if/switch 表达式(Swift 5.9+)
let emoji = if isHappy { "😊" } else { "😢" }
// count(where:)(Swift 6.0+)
let evens = [1, 2, 3, 4, 5].count(where: { $0.isMultiple(of: 2) }) // 2
// 正则字面量(Swift 5.7+)
let regex = /(\d{4})-(\d{2})-(\d{2})/
if let match = "2024-01-15".firstMatch(of: regex) {
print(match.1) // "2024"
}
// consume 关键字(Swift 5.9+)
func process(_ value: consuming String) {
// value 移入此函数,调用者不再拥有
}
常见面试问题
Q1: @Observable 和 ObservableObject 有什么区别?
答案:
| @Observable(Swift 5.9+) | ObservableObject | |
|---|---|---|
| 声明方式 | @Observable class | class: ObservableObject |
| 属性追踪 | 自动(无需标记) | 需要 @Published |
| View 绑定 | 直接使用 | @StateObject / @ObservedObject |
| 性能 | 只在被读取的属性变化时触发更新 | 任何 @Published 变化都触发 |
| 最低版本 | iOS 17+ | iOS 13+ |
Q2: Swift 6 的 Strict Concurrency 会带来什么影响?
答案:
Swift 6 将数据竞争检查从警告升级为编译错误。主要影响:
- 所有在并发上下文中共享的可变状态必须通过 Actor 或锁保护
- 跨并发域传递的值必须遵循
Sendable - 全局变量需要标记
@MainActor或nonisolated(unsafe) - 现有代码可能需要大量修改以通过编译
迁移策略:先在 Swift 5.10 中开启 strict concurrency 警告,逐步修复。
Q3: Macro 可以做什么,不可以做什么?
答案:
可以做:
- 在编译时生成代码(属性、方法、协议遵循等)
- 减少样板代码(
@Observable、@Model) - 编译时验证和转换
不可以做:
- 修改已有代码(只能添加)
- 访问运行时信息
- 产生副作用(文件操作等)