6-3.【架构设计】MVVM 在SwiftUI中是否仍然成立?在SwiftUI里,View/ViewModel的边界和UIKit有什么本质差异?

24 阅读2分钟

一、SwiftUI 中 MVVM 是否仍然成立?

答案:成立,但方式不同

  • Model:和 UIKit 一样,负责业务状态和数据逻辑

  • ViewModel:仍然负责:

    • 数据转换(格式化、过滤、排序)
    • 用户交互处理(逻辑/状态更新)
  • View:只负责声明 UI 和绑定状态

但是 SwiftUI 里 MVVM 的实现机制和 UIKit 不同

  • SwiftUI 的 View 是值类型(struct) ,每次状态改变都会重新生成
  • State/Binding/ObservedObject/EnvironmentObject 替代了 UIKit 的手动更新和生命周期管理
  • ViewModel 通常通过 ObservableObject + @Published 来驱动 View 更新

二、View/ViewModel 边界的本质差异

维度UIKitSwiftUI说明
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 式的“膨胀”问题

🔑 核心差异

  1. View 是轻量的值类型,不再承担状态

    • UIKit: View + VC = 状态 + 逻辑 + 展示
    • SwiftUI: View 只渲染,状态和逻辑放到 ViewModel
  2. 状态绑定自动驱动 UI

    • UIKit: 手动调用 reload/update
    • SwiftUI: @Published + @StateObject 自动刷新
  3. 生命周期解耦

    • 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 本质差异

  1. 轻量 View → 不存逻辑、不存状态
  2. 自动状态绑定 → 解除手动刷新压力
  3. ViewModel 生命周期解耦 → 避免 Massive ViewController 问题
  4. 声明式 UI → View 只是渲染函数,ViewModel 是“真正的逻辑容器”

可以说 SwiftUI 让 MVVM 回归“理论本意”:View 真正只管渲染,逻辑和状态完全在 ViewModel,不像 UIKit MVC/MVVM 那样天然会膨胀。


英文版

6-3. [Architecture Design] Is MVVM Still Valid in SwiftUI? What are the fundamental differences in the View/ViewModel boundaries between SwiftUI and UIKit?

I. Is MVVM Still Valid in SwiftUI?

Answer: Yes, but it works differently.

  • Model: Same as in UIKit; responsible for business state and data logic.

  • ViewModel: Still responsible for:

    • Data transformation (formatting, filtering, sorting).
    • Handling user interactions (logic/state updates).
  • View: Only responsible for declaring the UI and binding to the state.

However, the implementation mechanism of MVVM in SwiftUI differs from UIKit:

  1. View Type: SwiftUI Views are value types (struct). Every time the state changes, the view is re-generated.
  2. State Management: State / Binding / ObservedObject / EnvironmentObject replace the manual updates and lifecycle management found in UIKit.
  3. Driving Updates: The ViewModel typically drives View updates through ObservableObject + @Published.

II. Essential Differences in View/ViewModel Boundaries
DimensionUIKitSwiftUIExplanation
View TypeUIView / UIViewController (Reference Type)struct View (Value Type)SwiftUI Views don't hold state; they just render and respond to bindings.
View LifecycleExplicit (viewDidLoad, viewDidAppear, etc.)Reconstructed with state (structs created frequently)Views are no longer logic storage points and shouldn't hold business state.
State StorageViewController holds state (prone to bloating)@State, @StateObject, @ObservedObject hold stateState is detached from the View, stored in the ViewModel or SwiftUI system.
Binding MethodManual: Notifying VC to update (e.g., reloadData)Automatic: Declarative binding ($binding, @Published)Data flow drives UI; no manual refresh needed.
Lifecycle DependencyVC lifecycle is the natural container for logicViewModel lifecycle is independent of the ViewAvoids the "Massive View Controller" problem.

🔑 Core Differences:

  1. Lightweight Views: Views are lightweight value types and no longer carry state.

    • UIKit: View + VC = State + Logic + Presentation.
    • SwiftUI: View only renders; state and logic are moved to the ViewModel.
  2. Automatic Data Binding:

    • UIKit: Manual calls to reload/update.
    • SwiftUI: @Published + @StateObject automatically triggers refreshes.
  3. Decoupled Lifecycle:

    • UIKit: VC lifecycle acts as the state container, leading to "Massive VC."
    • SwiftUI: ViewModels can be bound to the View lifecycle via @StateObject or shared across layers via EnvironmentObject.

III. SwiftUI MVVM Implementation Example

Swift

// 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)
    }
}

IV. Summary of SwiftUI MVVM's Essential Differences
  1. Lightweight View: No logic, no state storage.
  2. Automatic Binding: Removes the pressure of manual UI refreshing.
  3. Decoupled Lifecycle: Prevents "Massive View Controller" issues.
  4. Declarative UI: The View is merely a rendering function, while the ViewModel is the "true container for logic."

Conclusion: One could say SwiftUI allows MVVM to return to its "theoretical roots": the View truly only cares about rendering, while logic and state reside entirely in the ViewModel, unlike UIKit where MVC/MVVM naturally tends to bloat.