跳到主要内容

Swift 新特性

问题

Swift 5.5 到 Swift 6.0 有哪些重要的新特性?Macro、Strict Concurrency、Noncopyable 类型分别是什么?

答案

Swift 版本新特性一览

版本核心特性
5.5async/await、Actor、Structured Concurrency
5.7if let 简写、some/any 关键字、正则字面量
5.9Macro、Parameter Pack(变参泛型)、~Copyable
5.10全局 Actor 隔离改进、Strict Concurrency 检查默认警告
6.0Strict 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类型安全的谓词构建
@ModelSwiftData 模型声明
// #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 classclass: ObservableObject
属性追踪自动(无需标记)需要 @Published
View 绑定直接使用@StateObject / @ObservedObject
性能只在被读取的属性变化时触发更新任何 @Published 变化都触发
最低版本iOS 17+iOS 13+

Q2: Swift 6 的 Strict Concurrency 会带来什么影响?

答案

Swift 6 将数据竞争检查从警告升级为编译错误。主要影响:

  1. 所有在并发上下文中共享的可变状态必须通过 Actor 或锁保护
  2. 跨并发域传递的值必须遵循 Sendable
  3. 全局变量需要标记 @MainActornonisolated(unsafe)
  4. 现有代码可能需要大量修改以通过编译

迁移策略:先在 Swift 5.10 中开启 strict concurrency 警告,逐步修复。

Q3: Macro 可以做什么,不可以做什么?

答案

可以做

  • 在编译时生成代码(属性、方法、协议遵循等)
  • 减少样板代码(@Observable@Model
  • 编译时验证和转换

不可以做

  • 修改已有代码(只能添加)
  • 访问运行时信息
  • 产生副作用(文件操作等)

相关链接