MVC(模型-视图-控制器)和 MVVM(模型-视图-视图模型)是帮助 Swift 开发者构建各类实用移动应用的常用软件架构。了解这两种模式的核心区别,能帮你为下一个项目选择更合适的方案。
在现代 iOS 应用开发中,你需要根据项目复杂度、团队开发经验、交付周期等因素,为项目和终端用户选择合适的架构模式。在做出选择前,你需要理解它们的工作原理、解决的问题,以及可能带来的问题。本文将对比 iOS 环境中最常用的两种移动架构:苹果官方与第三方开发者广泛使用的 MVC 模式,以及源自微软生态的 MVVM 模式。
什么是 MVC 架构模式?
MVC 即模型-视图-控制器,是一种将应用拆分为三大核心逻辑组件的架构模式,每个组件负责处理应用的特定功能。
MVC 模式将 iOS 应用的职责拆分到不同模块,把应用的业务逻辑与操作层和展示层分离,并通过控制器这个中间层协调模型与视图的交互,包括从数据库获取数据、处理数据,再将数据回传数据库或用于界面渲染。
MVC 模式组件
MVC 将代码组织为三层结构:
模型(Model):负责存储数据,不为视图需求处理数据,完全不感知视图的存在。模型数据是构建精准展示界面的核心。 视图(View):承担两项职责——向用户展示数据、接收用户操作。完全不感知模型,由其持有者(控制器)传入处理后的数据更新,因此视图不应包含任何业务逻辑。 控制器(Controller):持有并通信视图与模型层,负责用模型的处理数据更新模型和视图。最简场景下,控制器通常作为视图的代理,或为视图设置回调,基于用户操作更新模型与视图。
MVC 核心组件关系

MVC 优点
简单易用:组件数量少、定义清晰,是最易上手和维护的架构之一。 职责分离清晰:视图和模型的归属边界明确。 可复用性高:视图和模型与其他组件耦合度低,易于复用。 学习资源丰富:iOS 早期最常用架构,开发者认知度高,学习资料充足。
MVC 缺点
控制器臃肿:不属于视图、模型的逻辑都会堆在控制器中,导致“庞大视图控制器(Massive View Controller)”问题。 可测试性差:业务逻辑集中在与视图、模型强耦合的控制器中,难以编写有效的单元测试。 维护与拓展困难:控制器越臃肿,单元测试覆盖越难,应用维护和迭代成本越高。
什么是 MVVM 架构模式?
MVVM 即模型-视图-视图模型,是一种强化 UI 与业务逻辑/后端逻辑分离的架构模式。它和 MVC 一样包含模型、视图组件,但用视图模型替代控制器充当中介,实现更清晰的职责分离。
为解决 MVC 的问题,MVVM 在 MVC 基础上新增视图模型(ViewModel)层(控制器仍保留),模型和视图的职责与 MVC 完全一致。
MVVM 模式组件
模型(Model):同 MVC,存储数据,不感知视图,不为视图处理数据。 视图(View):同 MVC,展示数据、接收用户操作,无业务逻辑,不感知模型。 视图模型(ViewModel):模型与控制器之间的新增层,持有模型,将模型数据处理为视图可直接展示的格式;支持数据绑定,实现视图与模型的双向通信,自动同步数据变更。 控制器(Controller):仅负责搭建和协调所持组件,业务逻辑已移至视图模型,相比 MVC 更轻量化;控制器直接持有视图模型,而非模型。
MVVM 核心组件关系

MVVM 优点
职责分离更清晰:视图、模型的边界更明确。 可复用性高:视图、模型耦合度低,复用更便捷。 普及度高:虽比 MVC 新,但近年在 iOS 开发中广泛使用,学习资源充足。 可测试性大幅提升:业务逻辑移至视图模型,可通过模拟模型数据直接测试视图模型的属性与方法。 可扩展性强、复杂度更低:应用规模、功能、用户流程增长时,内部结构复杂度远低于 MVC;可通过代理、绑定、回调灵活与视图模型通信,引入协调器(Coordinator)抽离导航逻辑后可升级为 MVVM-C 架构。
MVC 与 MVVM 实现示例
以待办应用中展示单条任务的组件为例,对比 MVC 和 MVVM 的实现差异。
两者通用代码
模型、视图、视图代理完全一致:
// 任务模型
structTask {
var text: String
var isChecked: Bool
}
// 视图代理
protocolTaskViewDelegate {
funcdidTap()
}
// 任务视图
finalclassTaskView: UIView {
weakvar delegate: TaskViewDelegate?
privatelet imageView: UIImageView
privatelet label: UILabel
// 省略初始化与点击事件绑定
funcupdate(withimage: UIImage?, andattributedText: NSAttributedString) {
imageView.image = image
label.attributedText = attributedText
}
}
MVC 控制器实现
控制器持有模型,负责将数据转换为视图可消费的格式:
finalclassTaskViewController: UIViewController {
privatelet taskView: TaskView
privatelet attributes = [NSAttributedString.Key: Any]() // 演示用空属性
privatevar task: Task
// 省略视图搭建与初始更新
funcdidTap() {
task.isChecked.toggle()
updateView()
}
funcupdateView() {
let image =UIImage(named: task.isChecked ?"checkedTaskIcon" : "taskIcon")
let attributedText =NSAttributedString(string: task.text, attributes: attributes)
taskView.update(with: image, and: attributedText)
}
}
MVVM 视图模型与控制器实现
视图模型
持有模型,处理数据并暴露视图所需属性:
structTaskViewModel {
var image: UIImage? {
UIImage(named: task.isChecked ?"checkedTaskIcon" : "taskIcon")
}
var attributedText: NSAttributedString {
NSAttributedString(string: task.text, attributes: attributes)
}
privatelet attributes = [NSAttributedString.Key: Any]()
privatevar task: Task
init(task: Task) {
self.task = task
}
functoggleTask() {
task.isChecked.toggle()
}
}
视图模型单元测试示例
functestImage() {
// 给定测试数据
let task =Task(text: "Fixture Text", isChecked: true)
let sut =TaskViewModel(task: task)
// 验证结果
XCTAssertEqual(sut.image, UIImage(named: "checkedTaskIcon"))
}
MVVM 控制器实现
控制器仅协调视图与视图模型,逻辑大幅简化:
finalclassTaskViewController: UIViewController, TaskViewDelegate {
privatevar viewModel: TaskViewModel
// 省略视图搭建与初始更新
funcdidTap() {
viewModel.toggleTask()
updateView()
}
funcupdateView() {
taskView.update(with: viewModel.image, and: viewModel.attributedText)
}
}
MVC 与 MVVM 实现总结
新增视图模型层后,控制器逻辑显著精简,原本堆在控制器的代码被封装到职责明确的结构体中。
MVVM 的测试优势尤为明显:可直接测试视图模型;而 MVC 需通过视图测试控制器逻辑(属于集成测试而非单元测试),或牺牲代码可读性暴露控制器属性,测试维护成本随复杂度急剧上升。
全文总结
架构选择是移动应用开发的核心决策,需结合项目实际需求判断:
简单、无后续拓展计划的项目:MVC更合适,实现成本低、上手快。 需长期维护、持续拓展、重视单元测试的项目:MVVM更优,可避免控制器臃肿,降低测试与迭代成本。
没有通用的完美架构,只有适配项目需求的最佳选择。
夜雨聆风