iOS Architecture Skill
Overview
This skill covers Clean Architecture implementation for iOS applications with proper layer separation, dependency injection, and SOLID principles.
Architecture Layers
code
┌─────────────────────────────────────────────┐
│ Presentation Layer │
│ Views (SwiftUI) ←→ ViewModels (MVVM) │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Domain Layer │
│ Use Cases, Repositories, Business Logic │
└─────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────┐
│ Core Layer │
│ Stores (Actors), Networking, Persistence │
└─────────────────────────────────────────────┘
Dependency Rule
Dependencies point inward. Outer layers depend on inner layers, never the reverse.
code
UI → Domain → Core
(not the other way)
Layer Responsibilities
Core Layer (Core/)
- •Stores: Thread-safe state containers (Actors)
- •Networking: HTTP client abstraction
- •Persistence: Database operations
- •NO business logic
Domain Layer (CartDomain/, Auth/)
- •Repositories: Coordinate stores + API
- •Use Cases: Single-purpose business operations
- •Business Rules: Validation, transformation
- •Protocol definitions for external dependencies
Presentation Layer (UI/)
- •Views: SwiftUI declarative UI
- •ViewModels: Presentation logic, state binding
- •NO direct store access - use repositories
Protocol-Based Abstractions
swift
// Define protocol in Domain layer
public protocol HTTPClient: Actor {
func execute(_ request: HTTPRequest) async throws -> HTTPResponse
}
// Implement in Core layer
public actor URLSessionHTTPClient: HTTPClient {
public func execute(_ request: HTTPRequest) async throws -> HTTPResponse {
// Implementation
}
}
Composition Root Pattern
All dependencies wired in one place:
swift
@main
struct App: App {
init() {
// Create dependencies
let session = SessionStore()
let cartStore = CartStore()
let httpClient = URLSessionHTTPClient()
// Wire domain
let cartRepo = CartRepository(
store: cartStore,
outbox: OutboxStore(),
api: CartBackendClient(http: httpClient)
)
// Start services
CartSyncWorker(outbox: outbox, repo: cartRepo).start()
}
}
File Organization
code
Project/
├── Core/ # Foundation (no business logic)
│ ├── CoreNetworking.swift
│ ├── CoreSession.swift
│ └── CoreDatabase.swift
│
├── CartDomain/ # Business logic
│ ├── CartRepository.swift
│ └── CartSyncWorker.swift
│
├── CartData/ # External integrations
│ └── CartBackendClient.swift
│
└── UI/ # Presentation
├── Views.swift
└── ViewModels.swift
Anti-Patterns to Avoid
| Anti-Pattern | Correct Approach |
|---|---|
| View calls API directly | View → ViewModel → Repository |
| Repository imports UIKit | Domain layer is UI-agnostic |
| Concrete dependencies | Protocol-based abstractions |
| God ViewModel | Single responsibility ViewModels |