1️⃣ 值类型(struct + mutating)
安全性
- 天然线程安全:每个线程拿到的是 struct 的 独立副本,互不干扰。
- 快照语义:读写不会影响其他线程的数据副本。
- CoW 注意:如果 struct 内部含 CoW 容器(数组、字典、字符串),写入时可能触发复制,这复制可能在堆上,但仍然线程安全(因为 CoW 会先复制)。
性能
-
复制开销:
- 小 struct:开销极小,栈拷贝快。
- 大 struct(包含数组、buffer):每次修改可能触发 CoW,或者大量数据拷贝,CPU 和内存压力大。
-
批量更新可优化:局部变量修改后再整体赋值,减少 CoW。
并发场景建议
-
每个线程维护自己的 struct 副本 → 安全且无需锁
-
对共享大数组/CoW 容器,需要注意:
- 写操作触发 CoW → 堆分配 → 可能影响性能
- 多线程频繁写 → 每次可能触发 CoW → 性能下降
2️⃣ 引用类型(class + 共享对象)
安全性
-
默认线程不安全:
- 多线程访问同一个 class 对象时,读写可能冲突
- 需要加锁(
DispatchQueue,NSLock,actor)或者使用@MainActor/actor进行同步
-
共享状态:所有线程看到同一个实例的修改
性能
-
拷贝成本低:
- 无需复制 struct 的大字段
- 对大型 buffer/数组频繁修改非常高效
-
锁/同步开销:
- 多线程需要保护数据 → CPU 上下文切换或锁等待 → 性能可能下降
- 对于高频修改,如果锁粒度太大 → 可能成为瓶颈
并发场景建议
- 大对象需要频繁修改 → class 性能优越
- 多线程访问 → 使用细粒度锁或 actor/队列保证安全
- 内存共享 → 减少堆分配和 CoW
3️⃣ 对比总结表格
| 维度 | struct + mutating | class + 共享引用 |
|---|---|---|
| 线程安全 | 天然安全(独立副本) | 默认不安全,需要锁或 actor |
| 写入性能 | 小 struct快,大 struct触发 CoW慢 | 高,直接修改堆内存,无额外复制 |
| 内存开销 | 多副本 → 栈 + 堆 | 单实例 → 堆 + 引用 |
| 并发易用性 | 简单,无锁 | 复杂,需要锁或同步策略 |
| 最适用场景 | 并发读多写少,快照需求,UI state | 高频修改,大数据共享,多线程频繁写入 |
4️⃣ 核心权衡思路
-
安全优先 → struct
- 适合 SwiftUI、Redux 风格架构
- 快照、undo/redo、跨线程传递安全
-
性能优先 → class
- 适合大 buffer、频繁修改、多线程写入
- 必须加同步手段保证线程安全
-
混合策略
- 小字段用 struct 保持值语义
- 大字段或共享缓冲用 class 包装
- 结构清晰,读写性能可控,安全性可通过 actor 或锁保证
💡 实例示意:
// 高安全性版本(struct + mutating)
struct UIState {
var counter: Int
var data: [Int] // CoW
}
func update(state: inout UIState) {
state.counter += 1
}
// 高性能版本(class + 引用共享)
class UIStateClass {
var counter: Int = 0
var data: [Int] = []
let queue = DispatchQueue(label: "ui.state.queue")
func update() {
queue.sync { counter += 1 } // 同步写
}
}