iOS 架构面试中有一个经常被问到的问题。
“MVP 和 MVVM 有什么区别?”
两者都是让视图控制器更精简的模式,也都会在中间放置一个中间对象(Presenter/ViewModel)。只看结构图,似乎只是改了一个框的名称,所以这个问题其实很难回答。
今天,我们只用一个标准来总结两者的区别:“中间对象是否了解 View”。
MVP:Presenter 向 View 发出指令
在 MVP(Model-View-Presenter)中,Presenter了解 View。更准确地说,它引用的是 View 实现的协议(接口)。
protocol ProfileViewProtocol: AnyObject {
func showName(_ name: String)
func showLoading(_ isLoading: Bool)
}
final class ProfilePresenter {
weak var view: ProfileViewProtocol?
func load() {
view?.showLoading(true)
// ...数据加载后
view?.showName("张三")
view?.showLoading(false)
}
}
看出流程了吗?Presenter 处理数据后,直接命令 view:“显示这个”。View(视图控制器)实现协议方法,按指令绘制即可。
- 优点:流程明确、易于跟踪,完全不需要绑定框架。
- 缺点:屏幕元素越多,协议方法就会不断增加。
showName、showAge、showBadge……
MVVM:ViewModel 不知道 View 的存在
相比之下,MVVM(Model-View-ViewModel)的 ViewModel不会引用 View,只负责持有状态。
final class ProfileViewModel {
@Published private(set) var displayName = ""
@Published private(set) var isLoading = false
func load() {
isLoading = true
// ...数据加载后
displayName = "张三"
isLoading = false
}
}
不存在类似view?.showName(...)的调用。ViewModel 只更新自身状态,由 View 订阅(绑定)该状态并自动绘制。指令方向反过来了。
- MVP:向 View推送数据
- MVVM:View订阅并观察 ViewModel
因此,MVVM 实际上必须使用绑定方式(Combine、@Observable 等)。上一篇文章已经详细讲过为什么没有绑定的 MVVM 只是半成品。
看测试代码就能清楚看到区别
两种模式的目标都是“在没有屏幕的情况下测试逻辑”,但测试方式不同。
MVP 测试需要创建一个伪 View 并记录调用。
final class MockView: ProfileViewProtocol {
var shownName: String?
func showName(_ name: String) { shownName = name }
func showLoading(_ isLoading: Bool) {}
}
// presenter.load() 后 mockView.shownName 验证
MVVM 测试不需要 mock,只要检查状态值即可。
let vm = ProfileViewModel()
vm.load()
#expect(vm.displayName == "张三")
不需要协议,也不需要 mock 对象。这正是 ViewModel 不了解 View 所带来的实际好处。
那么,应该使用哪一个?
标准意外地简单:是否自然具备绑定方式。
- SwiftUI,或使用 Combine 的 UIKit → MVVM 很自然,因为绑定开箱即用。
- 引入绑定负担较大的旧版 UIKit → MVP 反而更实用。它只靠协议即可运行,流程明确,也更容易上手。
如今 MVVM 几乎成为 iOS 的标准,与其说是因为它比 MVP 更优越,不如说是因为Combine 和 @Observable 在框架层面得到了提供,消除了 MVVM 唯一的入门门槛:绑定。
总结
- MVP 与 MVVM 的本质区别只有一个。Presenter 了解 View(协议)并直接发出指令,而 ViewModel 不了解 View,只暴露状态。
- 因此,MVP 不需要绑定,而 MVVM 必须绑定。
- 在测试中,MVP 需要 mock View,而 MVVM 只需验证状态即可完成。
- 如果环境免费提供绑定(SwiftUI·Combine),就选择 MVVM;否则 MVP 也是很好的选择。
下一篇将介绍更进一步的模块拆分极端案例:VIPER。我们还会总结大型应用为何采用它,以及为何最终放弃它。

![[iOS 架构 #4] MVP 与 MVVM 的区别 封面图](/assets/images/posts/4b118d20-6c27-4d0a-ad4a-7ec1b68ffb16/1.jpg)