iOSコミュニティでは、何年も続いている熱い議論があります。
「SwiftUIにViewModelは必要?」
前回は、MVVMの核心はバインディングだと整理しました。SwiftUIにはバインディングがフレームワークに組み込まれています。そこで「ViewModelという層自体が重複なのでは」という主張が出てきました。いわゆるMV(Model-View)パターン派です。
シリーズ最終回となる今回は、双方の論拠を公平に検討し、実際に判断するための基準まで整理します。
SwiftUIのViewはすでにViewModelに似ている
UIKitでMVVMが必要だった理由を振り返ると、次のとおりです。
- UIViewControllerが肥大化したため、状態とロジックを外に出したかった
- 状態と画面を同期するバインディングが必要だった
しかしSwiftUIのViewは、そもそも状態の関数です。body状態を受け取り画面宣言を返すだけで、@State値が変わればフレームワークが自動的に再描画します。バインディングのためにCombineの購読コードを書く必要はありません。
さらにSwiftUIのViewはクラスではなく、値型のstructです。UIViewControllerのように数千行へ肥大化するライフサイクルの塊ではなく、レンダリングごとに作り直される軽量な設計図に近い存在です。
MV派の主張はここから始まります。Viewも肥大化せず、バインディングも無料なのに、画面ごとにViewModelクラスを作るのはUIKitの習慣を惰性で持ち込んでいるだけではないか、というわけです。
MV派の論拠
MVパターンでは画面ごとにViewModelを置かず、Viewが状態管理ツールを直接使います。
- 1つのViewに閉じた状態は
@Stateそこに置く - 複数画面で共有する状態は
@Observableモデルとして@Environment注入する - サーバーデータはModel層のstoreやclientが担当する
struct ProfileView: View {
@Environment(UserStore.self) private var store
@State private var isEditing = false
var body: some View {
List(store.posts) { PostRow(post: $0) }
.task { await store.loadPosts() }
}
}
Appleの公式サンプルコード(Fruta、Food Truckなど)も、おおむねこの構造です。画面ごとのViewModelではなく、ドメイン単位の@Observableモデルを複数のViewで共有します。
この方式の利点は明確です。画面ごとにクラスを作るボイラープレートがなくなり、@Stateや@Bindingといったフレームワークのツールを迂回せず直接使えます。
MVVM派の反論
反対側の論拠も決して軽くありません。
第一に、ロジックがViewに入り込みます。「投稿が0件で、読み込みが終わり、エラーがなければ案内文を表示する」といった条件がbody内に三項演算子として積み重なると、値型であっても読みにくくなります。
**第二に、テストの問題です。**Viewのbodyはユニットテストで実行しにくいものです。プレゼンテーションロジックがViewにあると、そのロジックもテストの盲点になります。ViewModelに分離すれば純粋なSwiftオブジェクトとしてすぐ検証できます。
**第三に、規模の問題です。**画面が数十個あり複数人で開発するアプリなら、状態とロジックの場所について一貫したルールが必要です。画面ごとにViewModelという決まった場所があるほうが、協業コストを下げられるという主張です。
名前ではなく依存方向
双方の論拠を見ると、この論争は「ViewModelというクラスがあるか」より、ロジックと状態がどこにあるかという問題です。この基準で考えれば、ほとんどのケースを整理できます。
- 1つのViewに閉じたUI状態(トグル、フォーカス、シートの表示状態)は
@StateViewに置きます。これをViewModelに出すのは過剰設計です。 - 複数画面で共有するドメイン状態は
@Observableモデルとして作り、注入します。Storeと呼ぶかViewModelと呼ぶかは本質ではありません。 - 画面用の加工ロジックが複雑になったら(フォーマット、表示条件、並べ替え・フィルタリング)、Viewの外にあるテスト可能な型へ分離します。それが実質的なViewModelです。
- いずれにせよ、ViewがネットワークやDBに直接触れないようにするという依存方向を守れば、MVかMVVMかは名前の違いに近いものです。
結局、「SwiftUIにViewModelは不要」という言葉の実態はこう要約できます。画面ごとに機械的にViewModelを作る必要はない。ただし、Viewの外に出すべきロジックがなくなるわけではない。
シリーズまとめ
3回にわたるiOSアーキテクチャシリーズを、各1行に圧縮すると次のとおりです。
- MVC:UIViewControllerがViewとControllerを兼ねるため、責務が集中する。小規模な画面では今も有効です。
- MVVM:画面状態をViewModelに分離し、バインディングで同期する。バインディングがなければ不完全です。
- MV論争:SwiftUIにはバインディングが組み込まれているため、画面ごとにViewModelを強制する理由はない。ただし、ロジックの置き場所と依存方向は依然として設計が必要です。
アーキテクチャは流行ではなく、チームとアプリの規模に合わせたトレードオフの選択です。反響があれば、VIPERやTCAのような、より重い選択肢も続けて扱います。

![[iOSアーキテクチャ #3] SwiftUIにViewModelは不要? MVパターン論争まとめのカバー画像](/assets/images/posts/7bedf164-d196-4a13-815a-c43b2968f9f4/1.jpg)