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,也會整理大型 App 為何導入它,以及為何後來離開它。

![[iOS 架構 #4] MVP 與 MVVM 的差異 封面圖](/assets/images/posts/4b118d20-6c27-4d0a-ad4a-7ec1b68ffb16/1.jpg)