architecture-patterns

Choose and implement iOS architecture patterns (MVVM, TCA, Clean Architecture) based on feature complexity. Use when designing architecture for new features or refactoring existing code.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "architecture-patterns" with this command: npx skills add dagba/ios-mcp/dagba-ios-mcp-architecture-patterns

Architecture Patterns

Overview

Quick reference for choosing and implementing iOS architecture patterns. Focused on decision criteria, not tutorials.

Pattern Selection

ComplexityPatternUse When
SimpleMVSingle screen, local state only
MediumMVVM2-5 screens, business logic, network calls
ComplexTCAState machines, side effects, complex flows
EnterpriseCleanMultiple 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)
  • @MainActor for 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-architecture skill 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.md
  • references/tca-guide.md
  • references/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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

programmatic-uikit-layout

No summary provided by upstream source.

Repository SourceNeeds Review
Security

swiftui-performance-audit

No summary provided by upstream source.

Repository SourceNeeds Review
General

swiftui-ui-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

swiftdata-coredata-persistence

No summary provided by upstream source.

Repository SourceNeeds Review