返回 Skill 列表
extension
分类: 开发与工程无需 API Key

swiftui-performance

诊断并修复SwiftUI性能问题,包括卡顿、停顿、启动缓慢、视图重绘过多以及应用程序终止。在对SwiftUI应用进行性能分析、调查UI响应性问题、优化渲染性能、减少启动时间或修复与内存相关的终止时,应使用此技能。触发条件包括SwiftUI性能问题、卡顿、停顿、不流畅、启动缓慢、内存不足(OOM)、看门狗终止、帧丢失或响应性问题。

person作者: jakexiaohubgithub

SwiftUI Performance

Comprehensive guide for diagnosing and fixing performance issues in SwiftUI apps. Based on Apple's Xcode performance documentation covering responsiveness, hangs, hitches, launch time, and terminations.

Issue Decision Tree

Start here to identify what type of performance problem you're dealing with:

Is the app unresponsive to touch/input?
├─ YES → HANG (main thread blocked >250ms)
│        See references/hangs-responsiveness.md
│
├─ NO, but scrolling/animations stutter?
│  → HITCH (frame delivered late)
│    See references/hitches-rendering.md
│
├─ NO, but app takes too long to appear?
│  → SLOW LAUNCH
│    See references/launch-terminations.md
│
├─ NO, but app gets killed by system?
│  → TERMINATION (OOM, watchdog, background timeout)
│    See references/launch-terminations.md
│
└─ NO, but views redraw too often / UI feels sluggish?
   → SWIFTUI VIEW PERFORMANCE
     See references/swiftui-views.md

Key Metrics

| Issue | Metric | Target | Tool | |-------|--------|--------|------| | Hang | Main thread block duration | <250ms | Time Profiler, MetricKit | | Hitch | Hitch time ratio (ms/s) | <5 ms/s | Hitches instrument | | Launch | Time to first frame (cold) | <400ms | App Launch template | | Frame | Render time per frame | <16ms (60fps) / <8ms (120fps) | Core Animation instrument | | Memory | Background footprint | <50MB | Allocations instrument | | Redraws | Body invocation count | Minimize per interaction | SwiftUI instrument |

Quick Patterns

Move work off main thread

// Use .task for async work — suspends, never blocks
.task {
    let result = await heavyOperation()
    self.data = result  // @MainActor auto-dispatch in SwiftUI
}

Prevent unnecessary view redraws

// Use @Observable (iOS 17+) for fine-grained invalidation
@Observable class Store {
    var count = 0
    var name = ""  // changing name won't redraw views that only read count
}

Use lazy containers for large datasets

ScrollView {
    LazyVStack {  // only materializes visible views
        ForEach(items) { item in ItemRow(item: item) }
    }
}

Avoid AnyView type erasure

// Use @ViewBuilder instead — preserves structural identity
@ViewBuilder
func content(for state: State) -> some View {
    switch state {
    case .loading: ProgressView()
    case .loaded(let data): DataView(data: data)
    case .error(let err): ErrorView(error: err)
    }
}

Defer non-critical launch work

func application(_ app: UIApplication, didFinishLaunchingWithOptions opts: ...) -> Bool {
    setupCriticalUI()  // only what's needed for first frame
    DispatchQueue.global(qos: .utility).async { Analytics.configure() }
    return true
}

Profiling Workflow

  1. Reproduce the issue on a physical device (Simulator hides real perf)
  2. Profile with Instruments (Product → Profile)
    • Hangs → Time Profiler or System Trace
    • Hitches → Animation Hitches template
    • Redraws → SwiftUI template
    • Launch → App Launch template
    • Memory → Allocations + Leaks
  3. Identify the bottleneck (main thread work, expensive body, excessive redraws)
  4. Fix using patterns from reference docs
  5. Measure again — use XCTest performance metrics for regression testing
// XCTest scroll hitch measurement
func testScrollPerformance() {
    let app = XCUIApplication()
    app.launch()
    measure(metrics: [XCTOSSignpostMetric.scrollDecelerationMetric]) {
        app.tables.firstMatch.swipeUp()
    }
}

Diagnostic Tools Reference

| Tool | What It Shows | When to Use | |------|---------------|-------------| | SwiftUI Instrument | Body invocations, attribute graph updates | Excessive redraws | | Time Profiler | CPU usage per thread | Hangs, slow operations | | System Trace | Thread states, waits, blocking | Lock contention, deadlocks | | Hitches Instrument | Frame delivery timing | Scroll/animation jank | | App Launch Template | dyld, static init, main thread phases | Slow startup | | Allocations | Memory growth, leaks | OOM terminations | | Xcode Organizer | Real-world metrics from shipped app | Field data analysis | | MetricKit | Programmatic hang/hitch/launch/crash data | Production monitoring |

Reference Docs

Detailed guidance by topic:

  • references/swiftui-views.md — View identity, dependency tracking, @Observable, body optimization
  • references/hangs-responsiveness.md — Main thread blocking, async patterns, hang prevention
  • references/hitches-rendering.md — Frame pipeline, commit vs render hitches, scroll performance
  • references/launch-terminations.md — Launch phases, cold/warm start, OOM, watchdog kills
  • references/diagnostic-tools.md — Instruments templates, MetricKit, XCTest metrics, os_signpost