swift-ui


# SwiftUI Guidelines

## 1 · State Management  
- **Primary pattern:** `@Observable` reference types for shared business logic.  
- Expose UI-bindable properties with `@Bindable`.  
- Inject view models via initialisers (`let model: …`); avoid global singletons.  
- `@State` → view-local, ephemeral values **only**.  
- `@Environment` → truly app- or scene-wide dependencies.  
- *Allowed with justification:* `@StateObject` / `@ObservableObject` for long-lived owners (e.g. caches).  
- Use `@Binding` only when two-way propagation is essential.  
- Never mix `@Published` with SwiftData; prefer computed or `@Transient` properties.

## 2 · Navigation  
- Default to `NavigationStack` + `navigationDestination(for:)` (value-typed routes).  
- Use `NavigationSplitView` for multicolumn layouts.  
- Persist path state outside the view when you need deep-link or state restoration.  
- Support universal links via `.navigationDestination(value:)`.

## 3 · Layout  
- Start with stacks (`H/V/ZStack`); escalate to `Grid` or custom `Layout` only when needed.  
- Use `ViewThatFits` and `containerRelativeFrame()` for adaptive sizing.  
- `GeometryReader` sparingly, for one-off measurements.  
- Text must respect Dynamic Type.

## 4 · Performance & Concurrency  
- Mark UI-touching code `@MainActor`; keep heavy work on background actors.  
- Use `TaskGroup`, `async let`, or streaming APIs for parallelism.  
- Prefer lazy containers (`LazyVStack`, `LazyHGrid`, `LazyForEach`) with stable IDs.  
- Pre-render heavy views with `ImageRenderer` when appropriate.  
- Profile in Instruments before optimising.

## 5 · Components, Interaction & Animation  
- `ScrollView` + `.scrollTargetBehavior()` for modern scrolling.  
- Standardise internal spacing with `.contentMargins()`.  
- Use SF Symbols 6 (variable width/colour) and animate via `.symbolEffect()`.  
- Trigger transitions with `.animation(value:)`; leverage phase-based animations for complex cases.  
- Provide haptics/audio via `.sensoryFeedback()`.  
- Respect `reduceMotion` in animation choices.

## 6 · Accessibility  
- Every element: `.accessibilityLabel`, `.accessibilityHint`, correct traits.  
- Combine related views with `.accessibilityElement(children: .combine)`.  
- Test with VoiceOver, large Dynamic Type, and colour-blind filters.  
- Respect reduced-motion settings.

## 7 · Project Structure & Testing  
- Keep a single Xcode target; add Swift Packages **only** for cross-app reuse or unit-test isolation.  
- Avoid `@_exported import` / `@_implementationOnly import`.  
- Each non-trivial View ships with a SwiftUI Preview *and* at least one unit test.

## 8 · Naming & Reserved Words  
- Don’t shadow Swift-Concurrency types (`Task`, `Actor`, `Sendable`) or std-lib (`Result`, `Error`).  

swiftui-mvvm


You are an expert in Swift 5.10+, Swift UI, and modern **MVVM** architecture for multi-platform Apple apps (iOS 18, iPadOS 18, visionOS 3, macOS 15, watchOS 12, tvOS 18). You design clean, scalable **Xcode** project layouts, teach best practices, and write production-ready code snippets.

repo-root/ ├─ .cursor/rules/ │ ├─ swift-ui.mdc │ └─ swiftui-mvvm.mdc ← this file ├─ <AppName>/ ← Swift / SwiftUI app sources │ ├─ App/ │ ├─ Assets.xcassets │ ├─ Features/ │ ├─ Shared/ │ ├─ ContentView.swift │ ├─ <AppName>.entitlements │ ├─ <AppName>App.swift │ └─ <AppName>.xcodeproj ├─ <AppName>Server/ ← Optional backend (if applicable) ├─ <AppName>Tests/ ← unit-test target └─ <AppName>UITests/ ← UI-test target


---

### Global Principles

1. **Follow Apple's API Design Guidelines**—clear naming, value semantics, small composable types.
2. Prefer **Swift Concurrency** (`async/await`, structured tasks, Actors) over callbacks.
3. Use **Combine** only where reactive streams add real value.
4. Build **all reusable code as local Swift Packages** and integrate **exclusively via SwiftPM**.
5. Keep every layer **platform-agnostic first**; conditional code only in the outermost view layer.
6. Treat the **ViewModel as a `@MainActor` observable reference type**; delegate IO to injected services.
7. Adhere to **SOLID** & **Clean Architecture** (View → ViewModel → UseCase → Repository → DataSource).
8. Maintain exhaustive **XCTest** + **XCUITest** suites and run them on every scheme.

---

### Recommended Xcode Project Layout *(rooted at `/<AppName>`)*

<AppName>/ ├─ App/ // @main entry point & SceneDelegate / App file │ └─ AppTheme.swift // global Appearance & Environment ├─ Shared/ // code compiled for every platform target │ ├─ Core/ │ │ ├─ Networking/ // URLSession, Codable, error types │ │ ├─ Persistence/ // CoreData / FileCache / Keychain │ │ └─ Services/ // business-level services & use cases │ └─ UIComponents/ // reusable SwiftUI views, modifiers, styles ├─ Features/ // one folder per vertical slice │ └─ <FeatureName>/ │ ├─ Model/ // domain & DTO types │ ├─ ViewModel/ // final @Observable class <Feature>VM │ ├─ View/ // SwiftUI screens & subviews │ └─ Tests/ // feature-scoped unit & UI tests (optional) ├─ Resources/ // Localizable.strings, JSON stubs, etc. ├─ Packages/ // local Swift packages (Sources/Tests) └─ XcodeGen.yml // optional spec to regenerate .xcodeproj


> **Tests**
>
> * Whole-app unit tests live at repo-root **`/<AppName>Tests`**.
> * UI tests live at repo-root **`/<AppName>UITests`**.
> * Feature-scoped tests may additionally live beside their feature source as shown above.

---

### Naming & Styling Conventions

| Element           | Convention (Swift)                        |
| ----------------- | ----------------------------------------- |
| Types             | **PascalCase** (`UserProfileViewModel`)   |
| Variables / funcs | **camelCase** (`isLoading`, `fetchPosts`) |
| Folder names      | **PascalCase** (`Networking`, `Features`) |
| Tests             | Mirror source path + **Tests** suffix     |

* **Indent = 4 spaces**, line-length ≤ 120.
* Group symbols with **`// MARK:`** (`State`, `Intent`, `Dependencies`, etc.).
* Everything is `private` by default—expose via protocols.
* Prefix state-mutating async funcs with **`@MainActor`**.

---

### ViewModel Template

```swift
@MainActor
@Observable final class FeedViewModel: ObservableObject {
    // MARK: - Published State
    var posts: [Post] = []
    var error: LocalizedError?

    // MARK: - Dependencies
    private let fetchFeedUseCase: FetchFeedUseCaseProtocol

    // MARK: - Lifecycle
    init(fetchFeedUseCase: FetchFeedUseCaseProtocol) {
        self.fetchFeedUseCase = fetchFeedUseCase
    }

    // MARK: - Intents
    func onAppear() async {
        do   { posts = try await fetchFeedUseCase.execute() }
        catch { error = error }
    }
}

Feature Scaffolding Workflow (Cursor-AI)

  1. Think step-by-step: outline folders/files to create inside <PLAN> tags (respect the project hierarchy).
  2. Confirm with the user; adjust if needed.
  3. Generate code/resources—no TODOs or placeholders.
  4. Update Package.swift & test targets automatically.
  5. Provide a short validation checklist (xcodebuild test, simple UI smoke test).

Testing Rules


Commit Hygiene


When in Doubt