在 iOS 架構的討論中,很少有模式像 VIPER 一樣引發如此兩極的評價。
有人稱它是「大型團隊協作的解答」,也有人稱它是「樣板碼地獄」。實際上,不少大型服務 App 曾在某個時期導入 VIPER 或其變體,幾年後又轉向更輕量的架構。
今天來整理 VIPER 想解決什麼問題,以及為什麼代價如此高昂。
VIPER 由五個部分組成
VIPER 將一個畫面拆成五種角色,名稱本身就是這五個角色的字首。
- View:負責顯示畫面,包含檢視控制器,只「負責繪製」。
- Interactor:商業邏輯。取得資料並套用規則。
- Presenter:View 與 Interactor 之間的中介,將資料加工成畫面所需的形式。
- Entity:純資料模型。
- Router(Wireframe):負責畫面轉場。
它把 MVC(Model-View-Controller)中原本由一個檢視控制器負責的工作拆成四部分,並將畫面轉場另外抽成 Router。也就是為系列第 1 篇提到的 Massive View Controller 每項責任都安排專屬位置。
核心規則是近似單向的嚴格參照關係。View 只知道 Presenter,Presenter 知道 Interactor 和 Router,而 Interactor 只接觸 Entity。各邊界以協定切開,因此任何部分都能替換成 mock。
有哪些改善?
這種架構確實有發揮光彩的時刻。
第一,能將測試涵蓋率提升到極致。所有邊界都是協定,因此 Interactor、Presenter、Router 都能各自獨立測試。
第二,大型團隊的分工更容易。每個畫面的結構都相同,因此可以預期「不論誰製作的畫面,檔案配置都一樣」。數十人共同維護一個程式碼庫時,這種一致性確實有價值。
第三,它很適合以功能為單位的模組化。一個畫面是自成一體的五個部分,因此容易依功能抽出模組。Uber 受 VIPER 啟發打造的 RIBs,就是將這個方向推到極致的案例:不是按 View,而是按商業邏輯單位將 App 拆成樹狀結構。
為什麼大家都離開了?
問題在於成本。
樣板碼多得驚人。即使是只有一個按鈕的畫面,View、Interactor、Presenter、Entity、Router,加上彼此之間的協定,也會產生六、七個檔案。「改一個標籤文字要經過三個檔案」之所以成為抱怨,並非沒有原因。
即使是簡單畫面,也會被強制承擔同樣的重量。靜態設定畫面和複雜動態消息畫面都一樣是五個部分。畫面的複雜度與架構重量並不成比例。
學習曲線與上手成本也不低。第一次看見資料沿著 View → Presenter → Interactor → Presenter → View 往返的人,需要一些時間才能追蹤這段流程。
而真正的致命一擊是SwiftUI 的出現。VIPER 源自 UIKit 時代「把責任從檢視控制器移出」的問題意識;但在 SwiftUI 中,View 本身已經很輕量,畫面轉場方式也不同,因此 Router 這類部分變得不自然。問題本身已經改變了。
所以 VIPER 是失敗的模式嗎?
很難這樣看。因為 VIPER 留下的遺產已融入現今的標準實務。
- 將畫面轉場交給專責物件 → 發展為 Coordinator 模式
- 將商業邏輯與呈現分離 → 發展為 UseCase/Repository 層
- 用協定切開邊界 → 發展為相依性注入與測試實務
完整使用 VIPER 五個部分的團隊變少了,但那五個部分各自想解決的問題與解法都保留了下來。現在更接近只挑選需要部分來使用的時代。
總結
- VIPER 將一個畫面分成 View、Interactor、Presenter、Entity、Router 五個部分,並以協定切開各邊界。
- 容易測試及大型團隊的一致性是它的優點,但每個畫面需要六、七個檔案,樣板碼成本很高。
- 進入 SwiftUI 時代後,問題意識本身改變了,因此完整採用原始 VIPER 的團隊變少。
- 不過,它的遺產仍以標準實務存留下來,例如 Router→Coordinator、Interactor→UseCase。
下一篇將介紹這項遺產中最普及的形式:Clean Architecture 的 UseCase 與 Repository 在 iOS 中實際負責什麼。

![[iOS 架構 #5] iOS VIPER 架構:大型 App 為何導入後又離開(直到 RIBs) 封面圖](/assets/images/posts/ef088d05-20c3-46e5-95b6-d23a695099e9/1.jpg)