Swiftのプロジェクト設計:MVVM, VIPER, Clean Architectureの違い
Swiftを使ってアプリを開発する際、プロジェクトの設計をどうするかは非常に重要です。
設計を適切に行うことで、可読性が向上し、保守しやすいコードを書くことができます。
- MVCでは限界を感じているけれど、他のアーキテクチャがよくわからない
- MVVM、VIPER、Clean Architectureといった設計パターンの違いを知りたい
- どのアーキテクチャを選べばいいのか判断に迷っている
自分の学習内容の整理も兼ねて、それぞれのアーキテクチャの特徴や違いを解説し、サンプルコードを交えて理解を深めていきます。
MVVMとは?
MVVM(Model-View-ViewModel)は、UIロジックとビジネスロジックを分離するためのアーキテクチャです。
構成要素
- Model(データ層): APIやデータベースから情報を取得。
- View(UI層): 画面の表示を担当。
- ViewModel(UIロジック層): ViewとModelの仲介役。
import Foundation
// Model
struct User {
let id: Int
let name: String
}
// ViewModel
class UserViewModel: ObservableObject {
@Published var userName: String = ""
func fetchUser() {
let user = User(id: 1, name: "Taro")
self.userName = user.name
}
}
import SwiftUI
// View
struct ContentView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
VStack {
Text(viewModel.userName)
Button("Fetch User") {
viewModel.fetchUser()
}
}
}
}
MVVMのメリット・デメリット
- UIとロジックの分離がしやすく、テストしやすい
- SwiftUIとの相性が良い
- 小規模なプロジェクトではオーバーヘッドが大きくなる可能性がある
VIPERとは?
VIPERは、責務を明確に分けることで、コードの可読性や再利用性を高める設計パターンです。
構成要素
- View(画面表示)
- Interactor(ビジネスロジック担当)
- Presenter(ViewとInteractorを橋渡し)
- Entity(データの定義)
- Router(画面遷移)
VIPERのサンプルコード
protocol UserInteractorProtocol {
func fetchUser() -> User
}
class UserInteractor: UserInteractorProtocol {
func fetchUser() -> User {
return User(id: 1, name: "Taro")
}
}
protocol UserPresenterProtocol {
func loadUser()
}
class UserPresenter: UserPresenterProtocol {
private let interactor: UserInteractorProtocol
private weak var view: UserViewProtocol?
init(view: UserViewProtocol, interactor: UserInteractorProtocol) {
self.view = view
self.interactor = interactor
}
func loadUser() {
let user = interactor.fetchUser()
view?.displayUserName(user.name)
}
}
protocol UserViewProtocol: AnyObject {
func displayUserName(_ name: String)
}
class UserViewController: UIViewController, UserViewProtocol {
var presenter: UserPresenterProtocol!
override func viewDidLoad() {
super.viewDidLoad()
presenter.loadUser()
}
func displayUserName(_ name: String) {
print("User Name: \(name)")
}
}
VIPERのメリット・デメリット
- 各コンポーネントの責務が明確で、拡張しやすい
- テストしやすい
- ファイル数が増え、小規模プロジェクトでは管理が難しくなることがある
Clean Architectureとは?
Clean Architectureは、アプリの依存関係を明確にし、テスト可能なコードを書くことを目的としています。
層の構成
- Entities(ビジネスルール)
- Use Cases(アプリケーション固有のロジック)
- Interface Adapters(データ変換やView)
- Frameworks & Drivers(iOSフレームワークや外部ライブラリ)
// Entity
struct User {
let id: Int
let name: String
}
// Use Case
protocol UserRepository {
func getUser() -> User
}
class GetUserUseCase {
private let repository: UserRepository
init(repository: UserRepository) {
self.repository = repository
}
func execute() -> User {
return repository.getUser()
}
}
// Adapter
class UserPresenter {
private let useCase: GetUserUseCase
init(useCase: GetUserUseCase) {
self.useCase = useCase
}
func fetchUserName() -> String {
return useCase.execute().name
}
}
Clean Architectureのメリット・デメリット
- 高いテスト容易性と拡張性
- 依存関係が整理され、スケーラブルな設計が可能
- 設計が複雑になり、小規模プロジェクトには不向き
まとめ
アーキテクチャ | 特徴 | 適用ケース |
---|---|---|
MVVM | シンプルでSwiftUI向き | 小~中規模のアプリ |
VIPER | 責務分離が明確 | 大規模アプリ・長期運用アプリ |
Clean Architecture | 依存関係が整理される | 超大規模アプリ |
プロジェクトの規模や目的に応じて、最適なアーキテクチャを選択した方がより良い雪渓と言えるのかも知れません。