一、SwiftUI 中 MVVM 是否仍然成立?
答案:成立,但方式不同
-
Model:和 UIKit 一样,负责业务状态和数据逻辑
-
ViewModel:仍然负责:
- 数据转换(格式化、过滤、排序)
- 用户交互处理(逻辑/状态更新)
-
View:只负责声明 UI 和绑定状态
但是 SwiftUI 里 MVVM 的实现机制和 UIKit 不同:
- SwiftUI 的 View 是值类型(struct) ,每次状态改变都会重新生成
- State/Binding/ObservedObject/EnvironmentObject 替代了 UIKit 的手动更新和生命周期管理
- ViewModel 通常通过
ObservableObject+@Published来驱动 View 更新
二、View/ViewModel 边界的本质差异
| 维度 | UIKit | SwiftUI | 说明 |
|---|---|---|---|
| View 类型 | UIView / UIViewController(引用类型) | struct View(值类型) | SwiftUI 的 View 不持有状态,只是渲染和响应绑定 |
| View 生命周期 | 明确(viewDidLoad / viewWillAppear / viewDidAppear / viewWillDisappear / deinit) | 随状态重建(struct 被频繁创建) | View 不再是逻辑存储点,不能放业务状态 |
| 状态存储 | ViewController 持有状态(容易膨胀) | @State、@StateObject、@ObservedObject 持有状态 | 使状态脱离 View 直接存于 ViewModel 或 SwiftUI 系统 |
| 绑定方式 | 手动:通知 VC 更新 View(reloadData、setNeedsLayout) | 自动:声明式绑定($binding、@Published、Combine) | 数据流驱动 UI,无需手动刷新 |
| 生命周期依赖 | VC 生命周期是逻辑天然容器 | ViewModel 生命周期独立于 View(@StateObject 生命周期通常绑定 View 层次,但不依赖 View 构造) | 避免了 VC 式的“膨胀”问题 |
🔑 核心差异
-
View 是轻量的值类型,不再承担状态
- UIKit: View + VC = 状态 + 逻辑 + 展示
- SwiftUI: View 只渲染,状态和逻辑放到 ViewModel
-
状态绑定自动驱动 UI
- UIKit: 手动调用 reload/update
- SwiftUI:
@Published+@StateObject自动刷新
-
生命周期解耦
- UIKit: VC 生命周期就是状态容器生命周期 → 导致 Massive VC
- SwiftUI: ViewModel 可以用
@StateObject绑定 View 生命周期,也可以用EnvironmentObject跨 View 层共享 → 避免膨胀
三、SwiftUI MVVM 实践示意
// Model
struct User {
let id: String
let name: String
}
// ViewModel
class UserViewModel: ObservableObject {
@Published var displayName: String = ""
private var user: User
init(user: User) {
self.user = user
self.displayName = "Name: (user.name)"
}
}
// View
struct UserView: View {
@StateObject var viewModel: UserViewModel
var body: some View {
Text(viewModel.displayName)
}
}
特点:
- View 只是声明 UI (
Text) - ViewModel 持有 Model(或快照),负责逻辑
- ViewModel 通过
@Published自动驱动 View 更新 - View 是 struct,每次状态变化可以安全重建
四、总结 SwiftUI MVVM 本质差异
- 轻量 View → 不存逻辑、不存状态
- 自动状态绑定 → 解除手动刷新压力
- ViewModel 生命周期解耦 → 避免 Massive ViewController 问题
- 声明式 UI → View 只是渲染函数,ViewModel 是“真正的逻辑容器”
可以说 SwiftUI 让 MVVM 回归“理论本意”:View 真正只管渲染,逻辑和状态完全在 ViewModel,不像 UIKit MVC/MVVM 那样天然会膨胀。