7-4.【高级特性】struct 在 SwiftUI 中为什么是首选?与性能和 diff 有何关系?

2 阅读3分钟

一、先给终极结论(面试版)

SwiftUI 必须依赖“值语义 + 不可变描述”,
struct 才能让 View 的 diff、重建和性能优化成立。

换句话说:

SwiftUI 的 View 不是“UI 对象”,而是“UI 描述快照”。


二、SwiftUI 的 View 到底是什么?

struct MyView: View {
    var body: some View {
        Text("Hello")
    }
}

⚠️ 关键点:

  • View 不是屏幕上的控件

  • 不是 UIView

  • 它只是一个:

    描述 UI 结构和状态依赖关系的值

每次状态变化,SwiftUI 会:

  1. 重新创建一棵 View 值树
  2. 和上一棵做 diff
  3. 计算最小 UI 更新

👉 View 的创建成本必须极低


三、为什么 struct 非常适合这件事?

1️⃣ 值语义 = 可预测的 diff

struct 有两个关键特性:

  • 不可变(语义上)
  • 拷贝即冻结状态
let old = MyView(count: 1)
let new = MyView(count: 2)
  • 两个 View 是两个独立值

  • SwiftUI 可以放心比较:

    • 字段是否变化
    • 结构是否一致

👉 这让 diff 成为“纯函数问题”


2️⃣ class 会破坏 diff 的基本假设 ❌

如果 View 是 class:

let v1 = MyView()
let v2 = v1
v2.count = 2

SwiftUI 会面对灾难级问题:

  • v1 === v2
  • 内部属性是否被偷偷改过?
  • 是否需要刷新 UI?
  • 谁在什么时候改的?

👉 引用语义 = 不可追踪的副作用


四、struct 与性能的直接关系

1️⃣ View 重建是“高频事件”

  • 状态变化
  • 父 View 更新
  • 环境值变化

SwiftUI 的策略是:

大量、频繁、廉价地重建 View

struct 非常适合:

structclass
分配栈 / 内嵌
ARC
创建成本极低
拷贝便宜 / COW增减引用计数

2️⃣ ARC 开销是 SwiftUI 的天敌

假设用 class:

  • 每次 body 计算:

    • retain / release
  • diff 阶段:

    • 比较引用关系
  • 状态传播:

    • 难以保证一致性

👉 ARC 抖动会直接体现在掉帧上


五、struct + diff 的核心关系

SwiftUI 的 diff 依赖三件事:

✅ 1. View 是纯值

  • 同样输入 → 同样输出
  • 无隐藏状态

✅ 2. View 构造是确定性的

var body: some View {
    if isOn {
        A()
    } else {
        B()
    }
}
  • 结构变化可预测
  • diff 可以按类型 + 位置匹配

✅ 3. identity 明确

  • ForEach(id:)
  • .id(_:)

👉 这些 都是值语义友好的设计


六、如果 SwiftUI 用 class,会发生什么?

直接说结论:几乎不可实现

问题包括:

  1. diff 无法信任对象内部是否变化
  2. 必须深度观察每个属性(KVO 噩梦)
  3. 状态同步复杂到不可控
  4. 性能极差(大量堆对象 + ARC)

这正是 UIKit 的模式:

  • 对象多
  • 生命周期复杂
  • 手动管理状态

SwiftUI 的目标正是反过来。


七、SwiftUI 中“真正的对象”在哪里?

关键点:

View 是 struct,但状态和副作用不是

角色类型
Viewstruct
状态class / actor
数据源ObservableObject
副作用Task / Actor
渲染目标UIKit / AppKit 对象
@StateObject var model = ViewModel()
  • ViewModel 是 class
  • 生命周期稳定
  • View 只是“读它”

👉 值描述 + 引用状态 = 平衡点


八、终极面试总结(建议原话背)

SwiftUI 的 View 必须是 struct,因为它是 UI 的值描述;
值语义让 View 的 diff 可预测、可比较、无副作用;
同时避免 ARC 开销,使得 SwiftUI 能高频重建 View 而不影响性能。