SwiftUI's actual mental model — view identity, lifetime, and dependencies (the Demystify canon), state ownership decision rules, Observation's per-property tracking, body-performance discipline, and the main-actor concurrency contract. Use when state resets mysteriously, views re-render too often, animations glitch between branches, choosing @State vs @Bindable vs plain property, or debugging "why did body run.
npx skills add https://github.com/rshankras/claude-code-apple-skills --skill data-flow
Nearly every confusing SwiftUI bug — state that resets, animations that crossfade instead of
move, lists that flash, bodies that run constantly — traces to identity, lifetime, or
dependencies. This is Apple's own mental model (the Demystify sessions + Data Essentials +
Observation), current through the WWDC26 @State macro.
ForEach misbehaving@State, @Binding, @Bindable, @Environment, plain propertySelf._printChanges(); concurrency warnings in view codeSwiftUI sees three things: identity, lifetime, dependencies. Views with the same identity
are "different states of the same conceptual UI element"; distinct identities are distinct views.
if/else creates **twoidentities** (_ConditionalContent) — flipping the branch destroys/recreates the view: state
resets, transitions crossfade instead of animating.
id: in ForEach or .id(_:) (also the target forScrollViewReader.scrollTo). Changing an explicit id is a new identity — new lifetime,
fresh state. (That's the .id(item.id) force-refresh trick — use it knowingly.)
over branching —
// ❌ two identities; state resets, transition crossfades
if expired { content.opacity(0.3) } else { content }
// ✅ one identity; cheap, pruned when inert
content.opacity(expired ? 0.3 : 1.0)
Inert values (opacity 1, padding 0) cost nothing. "By default, try to preserve identity."
struct instance; identity provides continuity.
@State/@StateObject storagetears down and reinitializes. If state "randomly resets," find the identity change.
@State is a macro with lazy initialization of @Observable classes (backportedto iOS 17) — the stored object initializes once per lifetime, not on every view-value init.
Remove default values when also assigning in init (source-breaking edge).
var id = UUID() computed per access (everything flashes/reanimates).Identifiable is for. Range ForEach(0..<n) only with a constant range.
if filter inside ForEach (0-or-1 views) or AnyViewforces List to resolve every row just to count them. Filter in the data, and cache the
filtered collection in the model — an inline .filter re-runs linearly on every body.
re-run, and value comparison prunes unchanged subtrees. Stable identity is "the backbone of
the dependency graph."
Image, not the wholemodel). Extracting subviews is free — "breaking up one view into multiple doesn't hurt
performance" — and shrinks invalidation scope.
@Observable) tracks per property, per instance — a view re-renders onlywhen a property it actually *read* changes, including through computed properties, arrays,
optionals, and nesting.
ObservableObject: drop conformance + @Published → @Observable;@ObservedObject → delete or @Bindable; @EnvironmentObject → @Environment.
Invalidation narrows from whole-object to read-properties — a free performance win.
Ask Apple's three questions: what data does the view need · how does it manipulate it ·
where does truth live?
| Situation | Use |
|---|---|
| Display-only, parent owns it | plain let property |
| Transient, view-local UI state | @State (group related fields into one struct with mutating methods) |
| Write access to someone else's truth | @Binding (bindings compose: $config.note) |
| Observable model owned by this view | @State (lazy-init since WWDC26 macro) |
| Observable model, needs $model.field bindings only | @Bindable |
| Observable model, globally available | @Environment |
| Observable model, none of the above | plain property |
@ObservedObject default — everyre-run reallocates it (heap churn, data loss); use @StateObject or @State + @Observable.
@State for the same value desync — lift state to the containerand hand children Bindings.
@SceneStorage (restoration state, per window) and @AppStorage (settings) are stores*next to* your model, not the model. Limit total sources of truth.
string-building; move loading to .task { await … }.
Self._printChanges() (or expression Self._printChanges() at anLLDB breakpoint): @self = view value changed; a named property = that dependency changed.
Debug-only — never ship it. Deeper workflow: performance/swiftui-debugging.
AnyView hides structure from SwiftUI (worse diagnostics/performance) — use@ViewBuilder helpers and switch instead.
View is @MainActor: body, @State, members, and Task { } created in body are allmain-actor — most view code needs zero annotations (and Swift 6.2's default-isolation mode
removes the rest).
Shape.path(in:), Layout methods,visualEffect, onGeometryChange — that's why they're Sendable. Don't touch
self.someState there; copy the value in the capture list ([pulse]) and compute from
the proxies SwiftUI hands you.
await can resume after the frame deadline, so time-sensitive state (gesture/scrollreactions, button loading indicators) must mutate synchronously *before* starting async work.
Bridge UI↔async through a piece of state; keep view Tasks minimal ("inform the model") so
async logic stays unit-testable.
Data-flow review: Symptom | Root cause (identity / lifetime / dependency / ownership) | Fix
— check identity first; it explains most of the rest.
performance/swiftui-debugging (Instruments workflow), swiftui/layout, swift/concurrency-patterns, ios/coding-best-practicesNon-animation creative direction for HyperFrames videos. Use for design spec (frame.md / design.md) handling, palettes, typography, narration, beat planning, audio-reactive visuals, composition patterns, and brand / style decisions. For atomic motion patterns and scene blueprints, use `hyperframes-animation`.
Brainstorm and write high-retention short-form video and carousel content for TikTok, Reels, and YouTube Shorts. Use whenever someone wants viral hook ideas, a video script or outline, content concepts for a product or topic, or wants to critique and improve a draft hook or script. Works for any storytime, listicle, carousel, or meme. Produces several diverse hook options from proven patterns, structures scripts for retention (hook, escalation, payoff, CTA), and adapts to each platform. Pattern-based guidance grounded in how short-form tends to perform; it improves the odds, it does not guarantee virality."
Generate short-form video ideas at volume and stop the blank-page problem for good. Use whenever someone says they're stuck for ideas, asks for 20 TikTok ideas or Reels ideas or YouTube Shorts ideas for their niche, wants a content brainstorm, needs help building a content pillar system or content matrix, wants to turn one idea into 5 angles, asks what to post this week, or wants a real idea generator workflow instead of staring at a notes app. Runs the systems prolific creators actually use: pillars, mining (comments, Reddit, search autocomplete, competitor outliers), repurposing, evergreen vs trend balance. Pattern-based guidance grounded in how short-form ideation tends to work; never run out of ideas is the goal, virality is not promised.
| This skill encodes Emil Kowalski's philosophy on UI polish, component design, animation decisions, and the invisible details that make software feel great.
Create and publish concise Rivet launch or changelog posts through an approval-gated workflow, including release research, a required user-selected hero variation, local HTML-rendered social and technical images, an R2 hero upload, MDX authoring, a reviewed draft GitHub PR for manual merge, and a scheduled and verified Buffer thread for @rivet_dev. Use when asked to launch, announce, ship, or prepare and schedule a Rivet feature or release announcement.
This skill encodes Emil Kowalski's philosophy on UI polish, component design, animation decisions, and the invisible details that make software feel great.
Generate a daily digest of today's policy-authorized meetings and voice memos — key decisions, action items, and themes across available recordings. Use when the user asks "recap my day", "what happened in my meetings today", "daily summary", "what did I discuss today", "any action items from today", or wants a consolidated view of the day's conversations.
Generate a daily digest of today's policy-authorized meetings and voice memos — key decisions, action items, and themes across available recordings. Use when the user asks "recap my day", "what happened in my meetings today", "daily summary", "what did I discuss today", "any action items from today", or wants a consolidated view of the day's conversations.
Take rshankras/data-flow from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.