debugging-instruments
This skill provides comprehensive debugging and performance profiling techniques for iOS apps using LLDB, Memory Graph Debugger, and Instruments. Use it when diagnosing crashes, memory leaks, retain cycles, main thread hangs, performance bottlenecks, and build failures, or when profiling CPU, memory, energy, and network usage in iOS applications.
git clone --depth 1 https://github.com/dpearson2699/swift-ios-skills /tmp/debugging-instruments && cp -r /tmp/debugging-instruments/skills/debugging-instruments ~/.claude/skills/debugging-instrumentsSKILL.md
# Debugging and Instruments
Diagnose crashes, memory leaks, retain cycles, main thread hangs, and performance bottlenecks in iOS apps using LLDB, Memory Graph Debugger, and Instruments. Covers breakpoint workflows, memory graph analysis, hang detection, build failure triage, and Instruments profiling for CPU, memory, energy, and network.
## Contents
- [LLDB Debugging](#lldb-debugging)
- [Memory Debugging](#memory-debugging)
- [Hang Diagnostics](#hang-diagnostics)
- [Build Failure Triage](#build-failure-triage)
- [Instruments Overview](#instruments-overview)
- [Common Mistakes](#common-mistakes)
- [Review Checklist](#review-checklist)
- [References](#references)
## LLDB Debugging
### Essential Commands
```text
(lldb) po myObject # Print object description (calls debugDescription)
(lldb) p myInt # Print with type info (uses LLDB formatter)
(lldb) v myLocal # Frame variable — fast, no code execution
(lldb) bt # Backtrace current thread
(lldb) bt all # Backtrace all threads
(lldb) frame select 3 # Jump to frame #3 in the backtrace
(lldb) thread list # List all threads and their states
(lldb) thread select 4 # Switch to thread #4
```
Use `v` over `po` when you only need a local variable value — it does not
execute code and cannot trigger side effects.
### Breakpoint Management
```text
(lldb) br set -f ViewModel.swift -l 42 # Break at file:line
(lldb) br set -n viewDidLoad # Break on function name
(lldb) br set -S setValue:forKey: # Break on ObjC selector
(lldb) br modify 1 -c "count > 10" # Add condition to breakpoint 1
(lldb) br modify 1 --auto-continue true # Log and continue (logpoint)
(lldb) br command add 1 # Attach commands to breakpoint
> po self.title
> continue
> DONE
(lldb) br disable 1 # Disable without deleting
(lldb) br delete 1 # Remove breakpoint
```
### Expression Evaluation
```text
(lldb) expr myArray.count # Evaluate Swift expression
(lldb) e -l swift -- import UIKit # Import framework in LLDB
(lldb) e -l swift -- self.view.backgroundColor = .red # Modify state at runtime
(lldb) e -l objc -- (void)[CATransaction flush] # Force UI update after changes
```
After modifying a view property in the debugger, call `CATransaction.flush()`
to see the change immediately without resuming execution.
### Watchpoints
```text
(lldb) w set v self.score # Break when score changes
(lldb) w set v self.score -w read # Break when score is read
(lldb) w modify 1 -c "self.score > 100" # Conditional watchpoint
(lldb) w list # Show active watchpoints
(lldb) w delete 1 # Remove watchpoint
```
Watchpoints are hardware-backed (limited to ~4 on ARM). Use them to find
unexpected mutations — the debugger stops at the exact line that changes
the value.
### Symbolic Breakpoints
Set breakpoints on methods without knowing the file. Useful for framework
or system code:
```text
(lldb) br set -n "UIViewController.viewDidLoad"
(lldb) br set -r ".*networkError.*" # Regex on symbol name
(lldb) br set -n malloc_error_break # Catch malloc corruption
(lldb) br set -n UIViewAlertForUnsatisfiableConstraints # Auto Layout issues
```
In Xcode, use the Breakpoint Navigator (+) to add symbolic breakpoints for
common diagnostics like `-[UIApplication main]` or `swift_willThrow`.
## Memory Debugging
### Memory Graph Debugger Workflow
1. Run the app in Debug configuration.
2. Reproduce the suspected leak (navigate to a screen, then back).
3. Tap the **Memory Graph** button in Xcode's debug bar.
4. Look for purple warning icons — these indicate leaked objects.
5. Select a leaked object to see its reference graph and backtrace.
Enable **Malloc Stack Logging** (Scheme > Diagnostics) before running so
the Memory Graph shows allocation backtraces.
### Common Retain Cycle Patterns
**Closure capturing self strongly:**
```swift
// LEAK — closure holds strong reference to self
class ProfileViewModel {
var onUpdate: (() -> Void)?
func startObserving() {
onUpdate = {
self.refresh() // strong capture of self
}
}
}
// FIXED — use [weak self]
func startObserving() {
onUpdate = { [weak self] in
self?.refresh()
}
}
```
**Strong delegate reference:**
```swift
// LEAK — strong delegate creates a cycle
protocol DataDelegate: AnyObject {
func didUpdate()
}
class DataManager {
var delegate: DataDelegate? // should be weak
}
// FIXED — weak delegate
class DataManager {
weak var delegate: DataDelegate?
}
```
**Timer retaining target:**
```swift
// LEAK — Timer.scheduledTimer retains its target
timer = Timer.scheduledTimer(
timeInterval: 1.0, target: self,
selector: #selector(tick), userInfo: nil, repeats: true
)
// FIXED — use closure-based API with [weak self]
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
self?.tick()
}
```
### Instruments: Allocations and Leaks
- **Allocations template**: Track memory growth over time. Use the
"Mark Generation" feature to isolate allocations created between
user actions (e.g., open/close a screen).
- **Leaks template**: Detects leaked allocations, including isolated retain
cycles the process can no longer reach. Run alongside Allocations for a
complete picture.
- Filter by your app's module name to exclude system allocations.
For leak or memory-growth triage, pair the tools: use Allocations **Mark
Generation** before and after the reproduction step to prove retained growth,
then use Memory Graph Debugger to inspect object ownership and Malloc Stack
Logging to recover allocation call stacks.
### Malloc Stack LoDiscover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery descriptors for BLE or Wi-Fi devices, handling accessory session events, migrating from CoreBluetooth permission-based scanning, or setting up accessories without requiring broad Bluetooth permissions.
Implement, review, or improve Live Activities and Dynamic Island experiences in iOS apps using ActivityKit. Use when building real-time updating widgets for the Lock Screen and Dynamic Island — delivery tracking, sports scores, ride-sharing status, workout timers, media playback, or any time-sensitive information that updates in real time. Also use when working with ActivityKit, ActivityAttributes, Activity lifecycle (request/update/end), Dynamic Island layouts (compact/minimal/expanded), push-to-update Live Activities, or Lock Screen live widgets.
Measure ad effectiveness with privacy-preserving attribution using AdAttributionKit. Use when registering ad impressions, handling attribution postbacks, updating conversion values, implementing re-engagement attribution, configuring publisher or advertiser apps, or replacing SKAdNetwork with AdAttributionKit for ad measurement.
Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple Watch system UI. Covers AlarmManager scheduling, AlarmAttributes and AlarmPresentation, AlarmButton stop and snooze actions, authorization, state observation, countdown widget-extension handoff, and Live Activity integration. Use when building wake-up alarms, countdown timers, or alarm-style alerts that need Apple's system alarm experience.
Build iOS App Clips with invocation URLs, App Clip Codes, NFC, QR codes, Safari banners, Maps, Messages, target setup, App Store Connect experiences, size/capability constraints, NSUserActivity routing, SKOverlay promotion, App Group/keychain handoff, ephemeral notifications, location confirmation, and full-app migration. Use when creating App Clips or wiring App Clip invocation, experience configuration, or full-app handoff.
Implement App Intents for Siri, Shortcuts, Spotlight, widgets, Control Center, and Apple Intelligence on iOS. Covers AppIntent actions, AppEntity and EntityQuery models, AppShortcutsProvider phrases, IndexedEntity Spotlight indexing, WidgetConfigurationIntent, SnippetIntent, and assistant schemas. Use when exposing app actions or entities to system surfaces.
Optimize App Store product pages for search visibility and conversion. Use for App Store Optimization (ASO), keyword research, app name/subtitle/keyword-field strategy, conversion-focused descriptions and promotional text, screenshot captions and ordering, Custom Product Pages with assigned search keywords, In-App Events, Product Page Optimization tests, localized metadata, ratings/review strategy, and in-app review prompt timing with RequestReviewAction or AppStore.requestReview. Also use when routing ASO vs App Store review, privacy/ATT, or StoreKit implementation boundaries.
Prepare for App Store review and prevent rejections. Covers App Store review guidelines, app rejection reasons, PrivacyInfo.xcprivacy privacy manifest requirements, required API reason codes, in-app purchase IAP and StoreKit rules, App Store Guidelines compliance, ATT App Tracking Transparency, EU DMA Digital Markets Act, HIG compliance checklist, app submission preparation, review preparation, metadata requirements, entitlements, widgets, and Live Activities review rules. Use when preparing for App Store submission, fixing rejection reasons, auditing privacy manifests, implementing ATT consent flow, configuring StoreKit IAP, or checking HIG compliance.