# Workflow: Optimize iOS App Performance
**Read NOW:**
1. references/performance.md
2. references/cli-observability.md
Measure first, optimize second. Never optimize based on assumptions.
## Step 1: Define the Problem
Ask:
- What feels slow?
- Startup? Scrolling? Specific action?
- When did it start?
## Step 2: Measure
**CPU Profiling:**
```bash
xcrun xctrace record \
--template 'Time Profiler' \
--device 'iPhone 16' \
--attach AppName \
--output profile.trace
```
**Memory:**
```bash
xcrun xctrace record --template 'Allocations' ...
```
**Launch time:**
```bash
# Add DYLD_PRINT_STATISTICS=1 to scheme environment
```
## Step 3: Identify Bottlenecks
Look for:
- Functions with high "self time"
- Main thread blocking
- Repeated expensive operations
- Large allocations
**SwiftUI re-renders:**
```swift
var body: some View {
let _ = Self._printChanges()
// ...
}
```
## Step 4: Common Optimizations
### Main Thread
```swift
// Bad
let data = expensiveWork() // blocks UI
// Good
let data = await Task.detached { expensiveWork() }.value
```
### SwiftUI
```swift
// Bad - rebuilds everything
struct BigView: View {
@State var a, b, c, d, e
}
// Good - isolated state
struct BigView: View {
var body: some View {
SubViewA() // has own @State
SubViewB() // has own @State
}
}
```
### Lists
```swift
// Use LazyVStack for long lists
ScrollView {
LazyVStack {
ForEach(items) { ... }
}
}
```
### Images
```swift
AsyncImage(url: url) { image in
image.resizable()
} placeholder: {
ProgressView()
}
```
## Step 5: Measure Again
Did it improve? If not, revert.
## Step 6: Performance Tests
```swift
func testScrollPerformance() {
measure(metrics: [XCTCPUMetric(), XCTMemoryMetric()]) {
// scroll simulation
}
}
```
| Metric | Target | Unacceptable |
|--------|--------|--------------|
| Launch | < 1s | > 2s |
| Scroll | 60 fps | < 30 fps |
| Response | < 100ms | > 500ms |