CtrlK
BlogDocsLog inGet started
Tessl Logo

dpearson2699/swift-ios-skills

Agent skills for iOS, iPadOS, Swift, SwiftUI, and modern Apple framework development.

80

Quality

100%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

architecture-patterns.mdskills/swift-architecture/references/

Architecture Pattern Recipes

Load this reference after the main skill selects a pattern. Keep feature behavior and dependency contracts stable while adopting these structures.

Contents

  • MVVM
  • MVI
  • TCA
  • Clean Architecture
  • Coordinator
  • VIPER

MVVM

Use a view model only when it owns presentation behavior rather than forwarding a model:

@MainActor @Observable
final class CheckoutViewModel {
    private let pricing: PricingService
    var items: [LineItem] = []
    var promoCode = ""

    var total: Decimal { pricing.total(for: items, promoCode: promoCode) }

    init(pricing: PricingService) { self.pricing = pricing }
}

Inject the service, test transformations and error states directly, and keep view-only focus/layout state in the view.

MVI

Define explicit state, user intents, and one transition/effect boundary:

struct SearchState: Equatable {
    var query = ""
    var results: [Result] = []
    var isLoading = false
}

enum SearchIntent { case queryChanged(String), submitted, response([Result]) }

@MainActor @Observable
final class SearchStore {
    private(set) var state = SearchState()
    func send(_ intent: SearchIntent) { /* reduce and launch bounded effects */ }
}

Test every state/intent pair, effect cancellation, and stale-response handling.

TCA

Model each feature with state, actions, a reducer body, and injected dependencies. Compose child reducers at feature boundaries and test with TestStore. Keep navigation state in the feature only when the route belongs to that feature. Check the current Composable Architecture documentation before copying macro or testing syntax because package APIs evolve independently of Apple SDKs.

Clean Architecture

Dependency direction points inward:

UI / presenters -> use cases -> domain entities
data adapters   -> repository protocols <- use cases

Keep domain types independent of SwiftUI, persistence, and networking. Introduce mapping only where it protects a real boundary; avoid one protocol per concrete type without a substitution need.

Coordinator

Use a coordinator as the route and child-flow owner in UIKit or hybrid apps:

@MainActor
protocol Coordinator: AnyObject {
    var children: [Coordinator] { get set }
    func start()
}

Retain child coordinators for the flow lifetime, remove them on completion, and keep business state in the feature model rather than the coordinator.

VIPER

Preserve existing responsibilities during maintenance:

  • View renders and forwards user events.
  • Interactor owns use-case logic.
  • Presenter maps results to view state.
  • Entity contains domain data.
  • Router owns UIKit navigation and module assembly.

When migrating away, replace one module boundary at a time and keep adapters until upstream callers use the new feature interface.

skills

swift-architecture

.mcp.json

README.md

tile.json