Back to Skills

swiftui-patterns

verified

Expert SwiftUI decisions: property wrapper selection (@State vs @StateObject vs @ObservedObject gotchas), navigation architecture (NavigationStack vs NavigationSplitView), performance traps (body recomputation, identity), and platform-specific patterns for tvOS focus. Use when building SwiftUI views for iOS/tvOS, debugging view update issues, or choosing navigation patterns. Trigger keywords: SwiftUI, @State, @StateObject, @ObservedObject, NavigationStack, sheet, animation, tvOS focus, view identity, body

View on GitHub

Marketplace

manifest-marketplace

Kaakati/rails-enterprise-dev

Plugin

reactree-ios-dev

development

Repository

Kaakati/rails-enterprise-dev
2stars

plugins/reactree-ios-dev/skills/swiftui-patterns/SKILL.md

Last Verified

January 25, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/Kaakati/rails-enterprise-dev/blob/main/plugins/reactree-ios-dev/skills/swiftui-patterns/SKILL.md -a claude-code --skill swiftui-patterns

Installation paths:

Claude
.claude/skills/swiftui-patterns/
Powered by add-skill CLI

Instructions

# SwiftUI Patterns — Expert Decisions

Expert decision frameworks for SwiftUI choices that require experience. Claude knows SwiftUI syntax — this skill provides the judgment calls that prevent subtle bugs.

---

## Decision Trees

### Property Wrapper Selection

```
Who creates the object?
├─ This view creates it
│  └─ Is it a value type (struct, primitive)?
│     ├─ YES → @State
│     └─ NO (class/ObservableObject)
│        └─ iOS 17+?
│           ├─ YES → @Observable class + var (no wrapper)
│           └─ NO → @StateObject
│
└─ Parent passes it down
   └─ Is it an ObservableObject?
      ├─ YES → @ObservedObject
      └─ NO
         └─ Need two-way binding?
            ├─ YES → @Binding
            └─ NO → Regular parameter
```

**The @StateObject vs @ObservedObject trap**: Using `@ObservedObject` for a locally-created object causes recreation on EVERY view update. State vanishes randomly.

```swift
// ❌ BROKEN — viewModel recreated on parent rerender
struct BadView: View {
    @ObservedObject var viewModel = UserViewModel()  // WRONG
}

// ✅ CORRECT — viewModel survives view updates
struct GoodView: View {
    @StateObject private var viewModel = UserViewModel()
}
```

### Navigation Pattern Selection

```
How many columns needed?
├─ 1 column (stack-based)
│  └─ NavigationStack with .navigationDestination
│
├─ 2 columns (list → detail)
│  └─ NavigationSplitView (2 column)
│     └─ iPad: sidebar + detail
│     └─ iPhone: collapses to stack
│
└─ 3 columns (sidebar → list → detail)
   └─ NavigationSplitView (3 column)
      └─ Mail/Files app pattern
```

**NavigationStack gotcha**: `navigationDestination(for:)` must be attached to a view INSIDE the NavigationStack, not on the NavigationStack itself. Wrong placement = silent failure.

```swift
// ❌ WRONG — destination outside stack hierarchy
NavigationStack {
    ContentView()
}
.navigationDestination(for: Item.self) { ... } // Never triggers!

// ✅ CORRECT — destination inside stack
NavigationStack {
    ContentVie

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
9418 chars