swift-refactor

Swift/SwiftUI Refactor (Modular MVVM-C)

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 "swift-refactor" with this command: npx skills add pproenca/dot-skills/pproenca-dot-skills-swift-refactor

Swift/SwiftUI Refactor (Modular MVVM-C)

Comprehensive refactoring guide for migrating Swift/SwiftUI code to modular MVVM-C with local SPM package boundaries and App-target composition root wiring.

Mandated Architecture Stack

┌───────────────────────────────────────────────────────────────┐ │ App target: DependencyContainer, Coordinators, Route Shells │ ├───────────────────────────────────────────────────────────────┤ │ Feature modules: View + ViewModel (Domain + DesignSystem deps)│ ├───────────────────────────────────────────────────────────────┤ │ Data package: repositories, remote/local stores, sync, retry │ ├───────────────────────────────────────────────────────────────┤ │ Domain package: models, repository/coordinator/error protocols │ └───────────────────────────────────────────────────────────────┘

Dependency Rule: Feature modules never import Data and never import sibling features.

Clinic Architecture Contract (iOS 26 / Swift 6.2)

All guidance in this skill assumes the clinic modular MVVM-C architecture:

  • Feature modules import Domain
  • DesignSystem only (never Data , never sibling features)
  • App target is the convergence point and owns DependencyContainer , concrete coordinators, and Route Shell wiring

  • Domain stays pure Swift and defines models plus repository, *Coordinating , ErrorRouting , and AppError contracts

  • Data owns SwiftData/network/sync/retry/background I/O and implements Domain protocols

  • Read/write flow defaults to stale-while-revalidate reads and optimistic queued writes

  • ViewModels call repository protocols directly (no default use-case/interactor layer)

When to Apply

Reference these guidelines when:

  • Migrating from deprecated SwiftUI APIs (ObservableObject, NavigationView, old onChange)

  • Restructuring state management to use @Observable ViewModels

  • Adding @Equatable diffing to views for performance

  • Decomposing large views into 10-node maximum bodies

  • Refactoring navigation to coordinator + route shell pattern

  • Refactoring to Domain/Data/Feature/App package boundaries

  • Setting up dependency injection through DependencyContainer

  • Improving list/collection scroll performance

  • Replacing manual Task management with .task(id:) and cancellable loading

Non-Negotiable Constraints (iOS 26 / Swift 6.2)

  • @Observable ViewModels/coordinators, ObservableObject / @Published never

  • NavigationStack is owned by App-target route shells and coordinators

  • @Equatable macro on every view, AnyView never

  • Domain defines repository/coordinator/error-routing protocols; no framework-coupled I/O

  • No dedicated use-case/interactor layer; ViewModels call repository protocols directly

  • Views never access repositories directly

Rule Categories by Priority

Priority Category Impact Prefix Rules

1 View Identity & Diffing CRITICAL diff-

4

2 API Modernization CRITICAL api-

7

3 State Architecture CRITICAL state-

6

4 View Composition HIGH view-

7

5 Navigation & Coordination HIGH nav-

5

6 Layer Architecture HIGH layer-

5

7 Architecture Patterns HIGH arch-

5

8 Dependency Injection MEDIUM-HIGH di-

2

9 Type Safety & Protocols MEDIUM-HIGH type-

4

10 List & Collection Performance MEDIUM list-

4

11 Async & Data Flow MEDIUM data-

3

12 Swift Language Fundamentals MEDIUM swift-

8

Quick Reference

  1. View Identity & Diffing (CRITICAL)
  • diff-equatable-views

  • Add @Equatable macro to every SwiftUI view

  • diff-closure-skip

  • Use @EquatableIgnored for closure properties

  • diff-identity-stability

  • Use stable O(1) identifiers in ForEach

  • diff-printchanges-debug

  • Use _printChanges() to diagnose re-renders

  1. API Modernization (CRITICAL)
  • api-observable-macro

  • Migrate ObservableObject to @Observable macro

  • api-navigationstack-migration

  • Replace NavigationView with NavigationStack

  • api-onchange-signature

  • Migrate to new onChange signature

  • api-environment-object-removal

  • Replace @EnvironmentObject with @Environment

  • api-alert-confirmation-dialog

  • Migrate Alert to confirmationDialog API

  • api-list-foreach-identifiable

  • Replace id: .self with Identifiable conformance

  • api-toolbar-migration

  • Replace navigationBarItems with toolbar modifier

  1. State Architecture (CRITICAL)
  • state-scope-minimization

  • Minimize state scope to nearest consumer

  • state-derived-over-stored

  • Use computed properties over redundant @State

  • state-binding-extraction

  • Extract @Binding to isolate child re-renders

  • state-remove-observation

  • Migrate @ObservedObject to @Observable tracking

  • state-onappear-to-task

  • Replace onAppear closures with .task modifier

  • state-stateobject-placement

  • Migrate @StateObject to @State with @Observable

  1. View Composition (HIGH)
  • view-extract-subviews

  • Extract subviews for diffing checkpoints

  • view-eliminate-anyview

  • Replace AnyView with @ViewBuilder or generics

  • view-computed-to-struct

  • Convert computed view properties to struct views

  • view-modifier-extraction

  • Extract repeated modifiers into custom ViewModifiers

  • view-conditional-content

  • Use Group or conditional modifiers over conditional views

  • view-preference-keys

  • Replace callback closures with PreferenceKey

  • view-body-complexity

  • Reduce view body to maximum 10 nodes

  1. Navigation & Coordination (HIGH)
  • nav-centralize-destinations

  • Refactor navigation to coordinator pattern

  • nav-value-based-links

  • Replace NavigationLink with coordinator routes

  • nav-path-state-management

  • Use NavigationPath for programmatic navigation

  • nav-split-view-adoption

  • Use NavigationSplitView for multi-column layouts

  • nav-sheet-item-pattern

  • Replace boolean sheet triggers with item binding

  1. Layer Architecture (HIGH)
  • layer-dependency-rule

  • Extract domain layer with zero framework imports

  • layer-usecase-protocol

  • Remove use-case/interactor layer; keep orchestration in ViewModel + repository protocols

  • layer-repository-protocol

  • Repository protocols in Domain, implementations in Data

  • layer-no-view-repository

  • Remove direct repository access from views

  • layer-viewmodel-boundary

  • Refactor ViewModels to expose display-ready state only

  1. Architecture Patterns (HIGH)
  • arch-viewmodel-elimination

  • Restructure inline state into @Observable ViewModel

  • arch-protocol-dependencies

  • Extract protocol dependencies through ViewModel layer

  • arch-environment-key-injection

  • Use Environment keys for service injection

  • arch-feature-module-extraction

  • Extract features into independent modules

  • arch-model-view-separation

  • Extract business logic into Domain models and repository-backed ViewModels

  1. Dependency Injection (MEDIUM-HIGH)
  • di-container-composition

  • Compose dependency container at app root

  • di-mock-testing

  • Add mock implementation for every protocol dependency

  1. Type Safety & Protocols (MEDIUM-HIGH)
  • type-tagged-identifiers

  • Replace String IDs with tagged types

  • type-result-over-optionals

  • Use Result type over optional with error flag

  • type-phantom-types

  • Use phantom types for compile-time state machines

  • type-force-unwrap-elimination

  • Eliminate force unwraps with safe alternatives

  1. List & Collection Performance (MEDIUM)
  • list-constant-viewcount

  • Ensure ForEach produces constant view count per element

  • list-filter-in-model

  • Move filter/sort logic from ForEach into ViewModel

  • list-lazy-stacks

  • Replace VStack/HStack with Lazy variants for unbounded content

  • list-id-keypath

  • Provide explicit id keyPath — never rely on implicit identity

  1. Async & Data Flow (MEDIUM)
  • data-task-modifier

  • Replace onAppear async work with .task modifier

  • data-error-loadable

  • Model loading states as enum instead of boolean flags

  • data-cancellation

  • Use .task automatic cancellation — never manage Tasks manually

  1. Swift Language Fundamentals (MEDIUM)
  • swift-let-vs-var

  • Use let for constants, var for variables

  • swift-structs-vs-classes

  • Prefer structs over classes

  • swift-camel-case-naming

  • Use camelCase naming convention

  • swift-string-interpolation

  • Use string interpolation for dynamic text

  • swift-functions-clear-names

  • Name functions and parameters for clarity

  • swift-for-in-loops

  • Use for-in loops for collections

  • swift-optionals

  • Handle optionals safely with unwrapping

  • swift-closures

  • Use closures for inline functions

How to Use

Read individual reference files for detailed explanations and code examples:

  • Section definitions - Category structure and impact levels

  • Rule template - Template for adding new rules

Reference Files

File Description

references/_sections.md Category definitions and ordering

assets/templates/_template.md Template for new rules

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.

General

zod

No summary provided by upstream source.

Repository SourceNeeds Review
General

clean-architecture

No summary provided by upstream source.

Repository SourceNeeds Review
General

emilkowal-animations

No summary provided by upstream source.

Repository SourceNeeds Review