architecture-patterns
Architecture Patterns
Overview
Quick reference for choosing and implementing iOS architecture patterns. Focused on decision criteria, not tutorials.
Pattern Selection
| Complexity | Pattern | Use When |
|---|---|---|
| Simple | MV | Single screen, local state only |
| Medium | MVVM | 2-5 screens, business logic, network calls |
| Complex | TCA | State machines, side effects, complex flows |
| Enterprise | Clean | Multiple teams, maximum modularity |
Decision Tree
1. Single screen + local state only?
→ MV (SwiftUI View + @State)
2. Business logic or shared state?
→ MVVM
3. Complex state transitions?
→ TCA
4. Multi-team, high modularity?
→ Clean Architecture
MVVM Pattern (Most Common)
Structure:
- ViewModels:
@Observable, protocol-based DI - Views:
@State private var viewModel - Services: Protocols for testability
Critical Rules:
- ✅ Protocol-based DI via init (enables mocking)
- ✅
@MainActorfor state updates - ✅ Keep Views dumb (delegate to ViewModel)
- ❌ Never import SwiftUI in ViewModels
- ❌ Never use
@Published(use@Observable) - ❌ Never make ViewModels optional
Minimal Example:
protocol AuthServiceProtocol {
func login(_ email: String, _ password: String) async throws -> User
}
@Observable
final class LoginViewModel {
private let authService: AuthServiceProtocol
var email = ""
var password = ""
var isLoading = false
init(authService: AuthServiceProtocol = AuthService()) {
self.authService = authService
}
@MainActor
func login() async {
isLoading = true
defer { isLoading = false }
try? await authService.login(email, password)
}
}
struct LoginView: View {
@State private var viewModel = LoginViewModel()
var body: some View {
Form {
TextField("Email", text: $viewModel.email)
SecureField("Password", text: $viewModel.password)
Button("Login") { Task { await viewModel.login() } }
.disabled(viewModel.isLoading)
}
}
}
TCA Pattern
Use for: Complex state machines, side effects, time-travel debugging
Key: Single Reducer with State/Action/Dependencies. Exhaustive testing via TestStore.
Reference: TCA documentation
Clean Architecture
Use for: Enterprise apps, multiple teams, maximum testability
Patterns:
- VIP (View-Interactor-Presenter): Use
vip-clean-architectureskill for unidirectional data flow, protocol-based boundaries, and Spy-pattern testing - Generic Clean: Domain (entities, use cases) → Data (repositories, network) → Presentation (ViewModels, Views)
Key: Dependency inversion, protocol-based boundaries between layers
References
For detailed implementation examples and migration guides, see:
references/mvvm-patterns.mdreferences/tca-guide.mdreferences/clean-architecture.md
Word count: ~300 (was 2,863) For: Senior/mid iOS engineers who know how to code Focus: Decision-making, not hand-holding
More from dagba/ios-mcp
swiftui-performance-audit
Audit and improve SwiftUI runtime performance from code review and architecture. Use for requests to diagnose slow rendering, janky scrolling, high CPU/memory usage, excessive view updates, or layout thrash in SwiftUI apps, and to provide guidance for user-run Instruments profiling when code review alone is insufficient.
62swiftui-ui-patterns
Best practices and example-driven guidance for building SwiftUI views and components. Use when creating or refactoring SwiftUI UI, designing tab architecture with TabView, composing screens, or needing component-specific patterns and examples.
52swiftdata-coredata-persistence
Use when implementing data persistence in iOS apps with SwiftData or CoreData, encountering migration errors, performance issues with fetches, or choosing between persistence frameworks
41programmatic-uikit-layout
Use when building UIKit interfaces without storyboards, setting up Auto Layout constraints with anchors, creating reusable UI components, or encountering layout constraint errors and ambiguous layout warnings
37macos-spm-app-packaging
Scaffold, build, and package SwiftPM-based macOS apps without an Xcode project. Use when you need a from-scratch macOS app layout, SwiftPM targets/resources, a custom .app bundle assembly script, or signing/notarization/appcast steps outside Xcode.
23swiftui-view-refactor
Refactor and review SwiftUI view files for consistent structure, dependency injection, and Observation usage. Use when asked to clean up a SwiftUI view’s layout/ordering, handle view models safely (non-optional when possible), or standardize how dependencies and @Observable state are initialized and passed.
22