Agent skill

swiftui-debugging

Diagnose SwiftUI performance issues including unnecessary re-renders, view identity problems, and slow body evaluations. Use when SwiftUI views are slow, janky, or re-rendering too often.

Stars 127
Forks 10

Install this agent skill to your Project

npx add-skill https://github.com/rshankras/claude-code-apple-skills/tree/main/skills/performance/swiftui-debugging

SKILL.md

SwiftUI Performance Debugging

Systematic guide for diagnosing and fixing SwiftUI performance problems: unnecessary view re-evaluations, identity issues, expensive body computations, and lazy loading mistakes.

When This Skill Activates

Use this skill when the user:

  • Reports slow or janky SwiftUI views
  • Sees excessive view re-renders or body re-evaluations
  • Asks about Self._printChanges() or view debugging
  • Has scrolling performance issues with lists or grids
  • Asks why a view keeps updating when nothing changed
  • Mentions @Observable or ObservableObject performance differences
  • Wants to understand SwiftUI view identity or diffing
  • Uses AnyView and asks about performance implications
  • Has a hang or stutter traced to SwiftUI rendering

Decision Tree

What SwiftUI performance problem are you seeing?
|
+- Views re-render when they should not
|  +- Read body-reevaluation.md
|     +- Self._printChanges() to identify which property changed
|     +- @Observable vs ObservableObject observation differences
|     +- Splitting views to narrow observation scope
|
+- Scrolling is slow / choppy (lists, grids)
|  +- Read lazy-loading.md
|     +- VStack vs LazyVStack, ForEach without lazy container
|     +- List prefetching, grid cell reuse
|
+- Views lose state unexpectedly / animate when they should not
|  +- Read view-identity.md
|     +- Structural vs explicit identity
|     +- .id() misuse, conditional view branching
|
+- Known pitfall (AnyView, DateFormatter in body, etc.)
|  +- Read common-pitfalls.md
|     +- AnyView type erasure, object creation in body
|     +- Over-observation, expensive computations
|
+- General "my SwiftUI app is slow" (unknown cause)
|  +- Start with body-reevaluation.md, then common-pitfalls.md
|  +- Use Instruments SwiftUI template (see Debugging Tools below)

API Availability

API / Technique Minimum Version Reference
Self._printChanges() iOS 15 body-reevaluation.md
@Observable iOS 17 / macOS 14 body-reevaluation.md
@ObservableObject iOS 13 body-reevaluation.md
LazyVStack / LazyHStack iOS 14 lazy-loading.md
LazyVGrid / LazyHGrid iOS 14 lazy-loading.md
.id() modifier iOS 13 view-identity.md
Instruments SwiftUI template Xcode 14+ SKILL.md
os_signpost iOS 12 SKILL.md

Top 5 Mistakes -- Quick Reference

# Mistake Fix Details
1 Large ForEach inside VStack or ScrollView without lazy container Wrap in LazyVStack -- eager VStack creates all views upfront lazy-loading.md
2 Using AnyView to erase types Use @ViewBuilder, Group, or concrete generic types -- AnyView defeats diffing common-pitfalls.md
3 Creating objects in body (DateFormatter(), NumberFormatter()) Use static let shared instances or @State for mutable objects common-pitfalls.md
4 Observing entire model when only one property is needed Split into smaller @Observable objects or extract subviews body-reevaluation.md
5 Unstable .id() values causing full view recreation every render Use stable identifiers (database IDs, UUIDs), never array indices or random values view-identity.md

Debugging Tools

Self._printChanges()

Add to any view body to see what triggered re-evaluation:

swift
var body: some View {
    let _ = Self._printChanges()
    // ... view content
}

Output reads: ViewName: @self, @identity, _propertyName changed. See body-reevaluation.md for full interpretation guide.

Instruments SwiftUI Template

  1. Xcode > Product > Profile (Cmd+I)
  2. Choose SwiftUI template (includes View Body, View Properties, Core Animation Commits)
  3. Record, reproduce the slow interaction, stop
  4. View Body lane shows which views had their body evaluated and how often
  5. View Properties lane shows which properties changed

os_signpost for Custom Measurement

swift
import os

private let perfLog = OSLog(subsystem: "com.app.perf", category: "SwiftUI")

var body: some View {
    let _ = os_signpost(.event, log: perfLog, name: "MyView.body")
    // ... view content
}

View in Instruments with the os_signpost instrument to count body evaluations per second.

Review Checklist

View Identity

  • No unstable .id() values (random, Date(), array index on mutable arrays)
  • Conditional branches (if/else) do not cause unnecessary view destruction
  • ForEach uses stable, unique identifiers from the model

Body Re-evaluation

  • Views observe only the properties they actually use
  • @Observable classes preferred over ObservableObject (iOS 17+)
  • No unnecessary @State changes that trigger body re-evaluation
  • Large views split into smaller subviews to narrow observation scope

Lazy Loading

  • Large collections use LazyVStack / LazyHStack, not VStack / HStack
  • List or lazy stack used for 50+ items
  • No .frame(maxHeight: .infinity) on children inside lazy containers (defeats laziness)

Common Pitfalls

  • No AnyView type erasure (use @ViewBuilder or Group)
  • No object allocation in body (DateFormatter, NSPredicate, view models)
  • Expensive computations moved to background with task { } or Task.detached
  • Images use AsyncImage or .resizable() with proper sizing, not raw UIImage decoding in body

Reference Files

File Content
view-identity.md Structural vs explicit identity, .id() usage, conditional branching
body-reevaluation.md What triggers body, _printChanges(), @Observable vs ObservableObject
lazy-loading.md Lazy vs eager containers, List, ForEach, grid performance
common-pitfalls.md AnyView, object creation in body, over-observation, expensive computations
../profiling/SKILL.md General Instruments profiling (Time Profiler, Memory, Energy)

Expand your agent's capabilities with these related and highly-rated skills.

rshankras/claude-code-apple-skills

legal

Legal document generation and compliance guidance for indie Apple developers. Covers privacy policies, terms of service, EULAs, GDPR/CCPA/DPDP compliance, and Apple App Store legal requirements. Use when user needs legal documents or compliance guidance.

127 10
Explore
rshankras/claude-code-apple-skills

privacy-policy

Generate privacy policies, terms of service, and EULAs for Apple platform apps. Detects data collection patterns, third-party SDKs, and generates region-specific legal documents with Apple Privacy Nutrition Label mapping. Use when user needs legal documents or data collection disclosure for App Store submission.

127 10
Explore
rshankras/claude-code-apple-skills

ios-development

Comprehensive iOS development guidance including Swift best practices, SwiftUI patterns, UI/UX review against HIG, and app planning. Use for iOS code review, best practices, accessibility audits, or planning new iOS apps.

127 10
Explore
rshankras/claude-code-apple-skills

assistive-access

Assistive Access implementation for cognitive accessibility including simplified scenes, navigation icons, runtime detection, and design principles. Use when optimizing apps for Assistive Access mode.

127 10
Explore
rshankras/claude-code-apple-skills

ui-review

Review SwiftUI code for iOS/watchOS Human Interface Guidelines compliance, font usage, Dynamic Type support, and accessibility. Use when user mentions UI review, HIG, accessibility audit, font checks, or wants to verify interface design against Apple standards.

127 10
Explore
rshankras/claude-code-apple-skills

navigation-patterns

SwiftUI navigation architecture patterns including NavigationStack, NavigationSplitView, TabView, programmatic navigation, and custom transitions. Use when reviewing or building navigation, fixing navigation bugs, or architecting app flow.

127 10
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results