SwiftUI Expert Skill
When to Use
Use when writing, reviewing, or refactoring SwiftUI code for iOS or macOS, including state management and @Observable data flow, view composition and invalidation/performance, lists and ForEach identity, environment usage, localization, animations, Liquid Glass adoption, migrating...
Operating Rules
- Consult
references/latest-apis.md at the start of every task to avoid deprecated APIs
- Prefer native SwiftUI APIs over UIKit/AppKit bridging unless bridging is necessary
- Focus on correctness and performance; do not enforce specific architectures (MVVM, VIPER, etc.)
- Encourage separating business logic from views for testability without mandating how
- Follow Apple's Human Interface Guidelines and API design patterns
- Only adopt Liquid Glass when explicitly requested by the user (see
references/liquid-glass.md)
- Present performance optimizations as suggestions, not requirements
- Use
#available gating with sensible fallbacks for version-specific APIs
Task Workflow
Review existing SwiftUI code
- Read the code under review and identify which topics apply
- Flag deprecated APIs (compare against
references/latest-apis.md)
- Run the Topic Router below for each relevant topic
- Validate
#available gating and fallback paths for iOS 26+ features
Improve existing SwiftUI code
- Audit current implementation against the Topic Router topics
- Replace deprecated APIs with modern equivalents from
references/latest-apis.md
- Refactor hot paths to reduce unnecessary state updates
- Extract complex view bodies into separate subviews
- Suggest image downsampling when
UIImage(data:) is encountered (optional optimization, see references/image-optimization.md)
Implement new SwiftUI feature
- Design data flow first: identify owned vs injected state
- Structure views for optimal diffing (extract subviews early)
- Apply correct animation patterns (implicit vs explicit, transitions)
- Use
Button for all tappable elements; add accessibility grouping and labels
- Gate version-specific APIs with
#available and provide fallbacks
Record a new Instruments trace
Trigger when the user asks to "record a trace", "profile the app", "capture a session", etc. Full reference: references/trace-recording.md.
- Confirm target — attach to a running app, launch an app, or record all processes? If the user didn't say, ask. List connected devices when useful:
python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices
- Pick a template based on target kind — the
SwiftUI template populates the SwiftUI lane on any real device: a physical iOS/iPadOS device or the host Mac. The only exception is the iOS Simulator, where the SwiftUI lane comes back empty — switch to --template "Time Profiler" in that case (still gives Time Profiler + Hangs + Animation Hitches). Always check --list-devices: simulators kind → Time Profiler; devices kind (real devices and the host Mac) → default SwiftUI. Full decision table in references/trace-recording.md.
- Start the recording. For agent-driven sessions where the user says "I'll tell you when I'm done", start in the background and use a stop-file:
python3 "${SKILL_DIR}/scripts/record_trace.py" \
--device "<name|udid>" --attach "<AppName>" \
--stop-file /tmp/stop-trace --output ~/Desktop/session.trace
For interactive sessions, just tell the user to press Ctrl+C when done.
- Signal stop — when the user says they've finished exercising the app,
touch /tmp/stop-trace. The script cleanly SIGINTs xctrace and waits up to 60s for finalisation.
- Analyse the resulting trace (flow into the "Trace-driven improvement" workflow below).
Trace-driven improvement (Instruments .trace provided)
Trigger whenever the user's request references a .trace file. A target SwiftUI source file is optional — if given, cite specific lines; if not, recommend where to look based on view names and symbols the trace already reveals.
Full reference: references/trace-analysis.md. Summary of the composition pattern:
- Scope the analysis. Ask yourself: does the user want the whole trace, or a slice?
- "focus on X / after X / between X and Y / during X" → resolve to a window first (see step 2).
- No scoping cue → analyse the whole trace.
- Resolve a window (only if the user scoped). The parser exposes two discovery modes:
# Find a log that marks the start/end of the region of interest:
python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \
--list-logs --log-message-contains "loaded feed" --log-limit 5
# Or list os_signpost intervals (paired begin/end), filterable by name:
python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \
--list-signposts --signpost-name-contains "ImageDecode"
Both modes accept --window START_MS:END_MS to scope discovery. Pick the time_ms (for logs) or start_ms/end_ms (for signposts) that match the user's description. Build a window like --window 10400:11700.
- Run the main analysis (with or without
--window):python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \
--json-only --top 10 [--window START_MS:END_MS]
- Interpret with
references/trace-analysis.md — key diagnostics:
main_running_coverage_pct inside each correlation (<25% = blocked; ≥75% = CPU-bound).
swiftui-causes.top_sources reveals why updates keep happening — high-edge-count sources like UserDefaultObserver.send() or wide EnvironmentWriter entries are structural invalidation bugs. Fixing one often collapses many downstream hot views.
- When a specific view shows as expensive, ask who's invalidating it. Use
--fanin-for "<view name>" to get the ranked list of source nodes driving the updates.
- Optionally ground in source. If the user pointed at a file, read it and match view names / user-code symbols against identifiers there. If not, recommend which files to open based on the view names SwiftUI reported.
- Return a prioritised plan. Cite evidence (coverage %, hot symbol, overlapping view, log timestamp, cause-graph edges) and route each recommendation to a Topic Router reference.
- Only edit code if the user asked for edits.
Topic Router
Consult the reference file for each topic relevant to the current task:
| Topic |
Reference |
| State management |
references/state-management.md |
| View composition |
references/view-structure.md |
| Performance |
references/performance-patterns.md |
| Lists and ForEach |
references/list-patterns.md |
| Layout |
references/layout-best-practices.md |
| Sheets and navigation |
references/sheet-navigation-patterns.md |
| ScrollView |
references/scroll-patterns.md |
| Focus management |
references/focus-patterns.md |
| Animations (basics) |
references/animation-basics.md |
| Animations (transitions) |
references/animation-transitions.md |
| Animations (advanced) |
references/animation-advanced.md |
| Accessibility |
references/accessibility-patterns.md |
| Swift Charts |
references/charts.md |
| Charts accessibility |
references/charts-accessibility.md |
| Image optimization |
references/image-optimization.md |
| Liquid Glass (iOS 26+) |
references/liquid-glass.md |
| macOS scenes |
references/macos-scenes.md |
| macOS window styling |
references/macos-window-styling.md |
| macOS views |
references/macos-views.md |
| Text patterns |
references/text-patterns.md |
| Localization |
references/localization.md |
| Deprecated API lookup |
references/latest-apis.md |
| Handling soft-deprecated APIs |
references/soft-deprecation.md |
| Previews |
references/previews.md |
| Instruments trace analysis |
references/trace-analysis.md |
| Instruments trace recording |
references/trace-recording.md |
Correctness Checklist
These are hard rules -- violations are always bugs:
References
references/latest-apis.md -- Read first for every task. Deprecated-to-modern API transitions (iOS 15+ through iOS 26+)
references/state-management.md -- Property wrappers, data flow, @Observable migration
references/view-structure.md -- View extraction, container patterns, @ViewBuilder
references/performance-patterns.md -- Hot-path optimization, update control, _logChanges()
references/list-patterns.md -- ForEach identity, Table (iOS 16+), inline filtering pitfalls
references/layout-best-practices.md -- Layout patterns, GeometryReader alternatives
references/accessibility-patterns.md -- VoiceOver, Dynamic Type, grouping, traits
references/animation-basics.md -- Implicit/explicit animations, timing, performance
references/animation-transitions.md -- View transitions, matchedGeometryEffect, Animatable
references/animation-advanced.md -- Phase/keyframe animations (iOS 17+), @Animatable macro (iOS 26+)
references/charts.md -- Swift Charts marks, axes, selection, styling, Chart3D (iOS 26+)
references/charts-accessibility.md -- Charts VoiceOver, Audio Graph, fallback strategies
references/sheet-navigation-patterns.md -- Sheets, NavigationSplitView, Inspector
references/scroll-patterns.md -- ScrollViewReader, programmatic scrolling
references/focus-patterns.md -- Focus state, focusable views, focused values, default focus, common pitfalls
references/image-optimization.md -- AsyncImage, downsampling, caching
references/liquid-glass.md -- iOS 26+ Liquid Glass effects and fallback patterns
references/macos-scenes.md -- Settings, MenuBarExtra, WindowGroup, multi-window
references/macos-window-styling.md -- Toolbar styles, window sizing, Commands
references/macos-views.md -- HSplitView, Table, PasteButton, AppKit interop
references/previews.md -- #Preview macro, @Previewable (iOS 18+), preview traits, mock data patterns for self-contained previews
references/text-patterns.md -- Text initializer selection, verbatim vs localized
references/localization.md -- String Catalogs, #bundle for packages, LocalizedStringResource, locale-aware formatting, RTL layout, translator comments
references/soft-deprecation.md -- How to behave with soft-deprecated APIs (when to migrate, scoping rule, don't migrate during unrelated edits)
references/trace-analysis.md -- Parse Instruments .trace files via scripts/analyze_trace.py; interpret main-thread coverage, high-severity SwiftUI updates, hitch narratives, and map findings back to source files
references/trace-recording.md -- Record a new trace via scripts/record_trace.py: attach to a running app, launch one fresh, or capture a manually-stopped session; supports stop-file for agent-driven flows
Limitations
- Use this skill only when the task clearly matches its upstream source and local project context.
- Verify commands, generated code, dependencies, credentials, and external service behavior before applying changes.
- Do not treat examples as a substitute for environment-specific tests, security review, or user approval for destructive or costly actions.
Source: sickn33/agentic-awesome-skills → skills/swiftui-expert-skill/SKILL.md
Also appears in: sickn33/agentic-awesome-skills/plugins/agentic-awesome-skills/skills/swiftui-expert-skill/SKILL.md, sickn33/agentic-awesome-skills/plugins/agentic-awesome-skills-claude/skills/swiftui-expert-skill/SKILL.md
1---2name: swiftui-expert-skill3description: Use when writing, reviewing, or refactoring SwiftUI code for iOS or macOS, including state management and `@Observable` data flow, view composition and invalidation/performance, lists and `ForEach` identity, environment usage, localization, animations, Liquid Glass adoption, migrating...4---567# SwiftUI Expert Skill8## When to Use910Use when writing, reviewing, or refactoring SwiftUI code for iOS or macOS, including state management and `@Observable` data flow, view composition and invalidation/performance, lists and `ForEach` identity, environment usage, localization, animations, Liquid Glass adoption, migrating...111213## Operating Rules1415- Consult `references/latest-apis.md` at the start of every task to avoid deprecated APIs16- Prefer native SwiftUI APIs over UIKit/AppKit bridging unless bridging is necessary17- Focus on correctness and performance; do not enforce specific architectures (MVVM, VIPER, etc.)18- Encourage separating business logic from views for testability without mandating how19- Follow Apple's Human Interface Guidelines and API design patterns20- Only adopt Liquid Glass when explicitly requested by the user (see `references/liquid-glass.md`)21- Present performance optimizations as suggestions, not requirements22- Use `#available` gating with sensible fallbacks for version-specific APIs2324## Task Workflow2526### Review existing SwiftUI code27- Read the code under review and identify which topics apply28- Flag deprecated APIs (compare against `references/latest-apis.md`)29- Run the Topic Router below for each relevant topic30- Validate `#available` gating and fallback paths for iOS 26+ features3132### Improve existing SwiftUI code33- Audit current implementation against the Topic Router topics34- Replace deprecated APIs with modern equivalents from `references/latest-apis.md`35- Refactor hot paths to reduce unnecessary state updates36- Extract complex view bodies into separate subviews37- Suggest image downsampling when `UIImage(data:)` is encountered (optional optimization, see `references/image-optimization.md`)3839### Implement new SwiftUI feature40- Design data flow first: identify owned vs injected state41- Structure views for optimal diffing (extract subviews early)42- Apply correct animation patterns (implicit vs explicit, transitions)43- Use `Button` for all tappable elements; add accessibility grouping and labels44- Gate version-specific APIs with `#available` and provide fallbacks4546### Record a new Instruments trace47Trigger when the user asks to "record a trace", "profile the app", "capture a session", etc. Full reference: `references/trace-recording.md`.48491. **Confirm target** — attach to a running app, launch an app, or record all processes? If the user didn't say, ask. List connected devices when useful:50 ```bash51 python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices52 ```532. **Pick a template based on target kind** — the `SwiftUI` template populates the SwiftUI lane on any **real device**: a physical iOS/iPadOS device **or the host Mac**. The only exception is the **iOS Simulator**, where the SwiftUI lane comes back empty — switch to `--template "Time Profiler"` in that case (still gives Time Profiler + Hangs + Animation Hitches). Always check `--list-devices`: `simulators` kind → `Time Profiler`; `devices` kind (real devices and the host Mac) → default `SwiftUI`. Full decision table in `references/trace-recording.md`.543. **Start the recording**. For agent-driven sessions where the user says "I'll tell you when I'm done", start in the background and use a stop-file:55 ```bash56 python3 "${SKILL_DIR}/scripts/record_trace.py" \57 --device "<name|udid>" --attach "<AppName>" \58 --stop-file /tmp/stop-trace --output ~/Desktop/session.trace59 ```60 For interactive sessions, just tell the user to press Ctrl+C when done.614. **Signal stop** — when the user says they've finished exercising the app, `touch /tmp/stop-trace`. The script cleanly SIGINTs xctrace and waits up to 60s for finalisation.625. **Analyse** the resulting trace (flow into the "Trace-driven improvement" workflow below).6364### Trace-driven improvement (Instruments `.trace` provided)65Trigger whenever the user's request references a `.trace` file. A target SwiftUI source file is **optional** — if given, cite specific lines; if not, recommend where to look based on view names and symbols the trace already reveals.6667Full reference: `references/trace-analysis.md`. Summary of the composition pattern:68691. **Scope the analysis.** Ask yourself: does the user want the whole trace, or a slice?70 - "focus on X / after X / between X and Y / during X" → **resolve to a window first** (see step 2).71 - No scoping cue → analyse the whole trace.722. **Resolve a window (only if the user scoped).** The parser exposes two discovery modes:73 ```bash74 # Find a log that marks the start/end of the region of interest:75 python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \76 --list-logs --log-message-contains "loaded feed" --log-limit 577 # Or list os_signpost intervals (paired begin/end), filterable by name:78 python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \79 --list-signposts --signpost-name-contains "ImageDecode"80 ```81 Both modes accept `--window START_MS:END_MS` to scope discovery. Pick the `time_ms` (for logs) or `start_ms`/`end_ms` (for signposts) that match the user's description. Build a window like `--window 10400:11700`.823. **Run the main analysis** (with or without `--window`):83 ```bash84 python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace <path> \85 --json-only --top 10 [--window START_MS:END_MS]86 ```874. **Interpret with `references/trace-analysis.md`** — key diagnostics:88 - `main_running_coverage_pct` inside each correlation (<25% = blocked; ≥75% = CPU-bound).89 - `swiftui-causes.top_sources` reveals *why* updates keep happening — high-edge-count sources like `UserDefaultObserver.send()` or wide `EnvironmentWriter` entries are structural invalidation bugs. Fixing one often collapses many downstream hot views.905. **When a specific view shows as expensive, ask who's invalidating it.** Use `--fanin-for "<view name>"` to get the ranked list of source nodes driving the updates.916. **Optionally ground in source.** If the user pointed at a file, read it and match view names / user-code symbols against identifiers there. If not, recommend which files to open based on the view names SwiftUI reported.927. **Return a prioritised plan.** Cite evidence (coverage %, hot symbol, overlapping view, log timestamp, cause-graph edges) and route each recommendation to a Topic Router reference.938. Only edit code if the user asked for edits.9495### Topic Router9697Consult the reference file for each topic relevant to the current task:9899| Topic | Reference |100|-------|-----------|101| State management | `references/state-management.md` |102| View composition | `references/view-structure.md` |103| Performance | `references/performance-patterns.md` |104| Lists and ForEach | `references/list-patterns.md` |105| Layout | `references/layout-best-practices.md` |106| Sheets and navigation | `references/sheet-navigation-patterns.md` |107| ScrollView | `references/scroll-patterns.md` |108| Focus management | `references/focus-patterns.md` |109| Animations (basics) | `references/animation-basics.md` |110| Animations (transitions) | `references/animation-transitions.md` |111| Animations (advanced) | `references/animation-advanced.md` |112| Accessibility | `references/accessibility-patterns.md` |113| Swift Charts | `references/charts.md` |114| Charts accessibility | `references/charts-accessibility.md` |115| Image optimization | `references/image-optimization.md` |116| Liquid Glass (iOS 26+) | `references/liquid-glass.md` |117| macOS scenes | `references/macos-scenes.md` |118| macOS window styling | `references/macos-window-styling.md` |119| macOS views | `references/macos-views.md` |120| Text patterns | `references/text-patterns.md` |121| Localization | `references/localization.md` |122| Deprecated API lookup | `references/latest-apis.md` |123| Handling soft-deprecated APIs | `references/soft-deprecation.md` |124| Previews | `references/previews.md` |125| Instruments trace analysis | `references/trace-analysis.md` |126| Instruments trace recording | `references/trace-recording.md` |127128## Correctness Checklist129130These are hard rules -- violations are always bugs:131132- [ ] `@State` properties are `private`133- [ ] `@Binding` only where a child modifies parent state134- [ ] Passed values never declared as `@State` or `@StateObject` (they ignore updates)135- [ ] `@StateObject` for view-owned objects; `@ObservedObject` for injected136- [ ] iOS 17+: `@State` with `@Observable`; `@Bindable` for injected observables needing bindings137- [ ] `ForEach` uses stable identity (never `.indices`/`\.offset`; id outlives the view and isn't derived from mutable content)138- [ ] Constant number of views per `ForEach` element; `List` rows are unary139- [ ] No closures stored in custom `@Environment`/`@FocusedValue` keys140- [ ] Custom `@Entry` default values are stable (no `Model()`/`Date()`/`UUID()` expressions)141- [ ] `.animation(_:value:)` always includes the `value` parameter142- [ ] `@FocusState` properties are `private`143- [ ] No redundant `@FocusState` writes inside tap gesture handlers on `.focusable()` views144- [ ] iOS 26+ APIs gated with `#available` and fallback provided145- [ ] `import Charts` present in files using chart types146- [ ] Previews use self-contained mock data; no dependency on live services or network147148## References149150- `references/latest-apis.md` -- **Read first for every task.** Deprecated-to-modern API transitions (iOS 15+ through iOS 26+)151- `references/state-management.md` -- Property wrappers, data flow, `@Observable` migration152- `references/view-structure.md` -- View extraction, container patterns, `@ViewBuilder`153- `references/performance-patterns.md` -- Hot-path optimization, update control, `_logChanges()`154- `references/list-patterns.md` -- ForEach identity, Table (iOS 16+), inline filtering pitfalls155- `references/layout-best-practices.md` -- Layout patterns, GeometryReader alternatives156- `references/accessibility-patterns.md` -- VoiceOver, Dynamic Type, grouping, traits157- `references/animation-basics.md` -- Implicit/explicit animations, timing, performance158- `references/animation-transitions.md` -- View transitions, `matchedGeometryEffect`, `Animatable`159- `references/animation-advanced.md` -- Phase/keyframe animations (iOS 17+), `@Animatable` macro (iOS 26+)160- `references/charts.md` -- Swift Charts marks, axes, selection, styling, Chart3D (iOS 26+)161- `references/charts-accessibility.md` -- Charts VoiceOver, Audio Graph, fallback strategies162- `references/sheet-navigation-patterns.md` -- Sheets, NavigationSplitView, Inspector163- `references/scroll-patterns.md` -- ScrollViewReader, programmatic scrolling164- `references/focus-patterns.md` -- Focus state, focusable views, focused values, default focus, common pitfalls165- `references/image-optimization.md` -- AsyncImage, downsampling, caching166- `references/liquid-glass.md` -- iOS 26+ Liquid Glass effects and fallback patterns167- `references/macos-scenes.md` -- Settings, MenuBarExtra, WindowGroup, multi-window168- `references/macos-window-styling.md` -- Toolbar styles, window sizing, Commands169- `references/macos-views.md` -- HSplitView, Table, PasteButton, AppKit interop170- `references/previews.md` -- `#Preview` macro, `@Previewable` (iOS 18+), preview traits, mock data patterns for self-contained previews171- `references/text-patterns.md` -- Text initializer selection, verbatim vs localized172- `references/localization.md` -- String Catalogs, `#bundle` for packages, `LocalizedStringResource`, locale-aware formatting, RTL layout, translator comments173- `references/soft-deprecation.md` -- How to behave with soft-deprecated APIs (when to migrate, scoping rule, don't migrate during unrelated edits)174- `references/trace-analysis.md` -- Parse Instruments `.trace` files via `scripts/analyze_trace.py`; interpret main-thread coverage, high-severity SwiftUI updates, hitch narratives, and map findings back to source files175- `references/trace-recording.md` -- Record a new trace via `scripts/record_trace.py`: attach to a running app, launch one fresh, or capture a manually-stopped session; supports stop-file for agent-driven flows176177## Limitations178179- Use this skill only when the task clearly matches its upstream source and local project context.180- Verify commands, generated code, dependencies, credentials, and external service behavior before applying changes.181- Do not treat examples as a substitute for environment-specific tests, security review, or user approval for destructive or costly actions.182183---184185**Source:** [`sickn33/agentic-awesome-skills`](https://github.com/sickn33/agentic-awesome-skills) → `skills/swiftui-expert-skill/SKILL.md`186187**Also appears in:** `sickn33/agentic-awesome-skills/plugins/agentic-awesome-skills/skills/swiftui-expert-skill/SKILL.md`, `sickn33/agentic-awesome-skills/plugins/agentic-awesome-skills-claude/skills/swiftui-expert-skill/SKILL.md`