---
description: Swift Performance
alwaysApply: false
---

# Swift Performance

Profile first. Understand ARC, value types, and Instruments. Optimize what matters.

## Profile Before Optimizing

Use Instruments (Product → Profile ⌘I):
- **Time Profiler** — CPU hotspots
- **Allocations** — memory usage and leaks
- **Leaks** — retain cycles
- **Core Animation** — rendering performance

## ARC and Retain Cycles

```swift
// Weak references break retain cycles
cancellable = publisher.sink { [weak self] value in
    self?.handleValue(value)
}

// Capture lists — be explicit
Task { [weak self, userId = self.user.id] in
    guard let self else { return }
    let data = try await self.fetch(userId: userId)
}
```

## Collection Performance

```swift
// Reserve capacity for known sizes
var results: [ProcessedItem] = []
results.reserveCapacity(items.count)

// Lazy for chained operations on large collections
let names = users.lazy.filter { $0.isActive }.map { $0.fullName }.prefix(10)

// Set for O(1) membership tests
let activeIds = Set(activeUsers.map(\.id))
let filtered = orders.filter { activeIds.contains($0.userId) }
```

## SwiftUI Performance

- Use `@Observable` (iOS 17+) over `ObservableObject` — property-level tracking
- `LazyVStack`/`LazyHStack` for large lists — only creates visible views
- Prefer `let` over `@State` for display-only data
- Equatable conformance on expensive views to skip redundant diffs

## Key Rules

- Value types for stack allocation, no ARC overhead
- `[weak self]` in closures to prevent retain cycles
- `reserveCapacity` for collections with known sizes
- Batch actor operations to reduce actor hops

## Anti-Patterns

```swift
// Never: Premature optimization without Instruments profiling
// Never: Classes where structs work — unnecessary heap/ARC overhead
// Never: String concatenation with + in loops — O(n²)
// Never: Capturing self strongly in long-lived closures — retain cycle
```
