debugging-instruments
Debug iOS apps and profile performance using LLDB, Memory Graph Debugger, and Instruments. Use when diagnosing crashes, memory leaks, retain cycles, main thread hangs, slow rendering, build failures, or when profiling CPU, memory, energy, and network usage.
What this skill does
# 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 Logging
Enable in Scheme > Run > Diagnostics > Malloc Stack Logging. This records
allocation backtraces so the Memory Graph Debugger, Allocations instrument,
and exported `.memgraph` files can show where objects were created.
```bash
# Inspect an exported memory graph from Xcode or Instruments
leaks MyApp.memgraph
```
## Hang Diagnostics
### Identifying Main Thread Hangs
For discrete interactions, delays under 100 ms are rarely noticeable; a few
hundred milliseconds can make an app feel unresponsive. Apple developer tools
typically start reporting main-run-loop busy periods over 250 ms. Common
detection tools:
- **Thread Checker** (Xcode Diagnostics): warns about non-main-thread UI calls
- **Thread Performance Checker**: reports priority inversions while debugging
- **On-device Hang Detection**: Developer Settings reports hangs from device use
- **Time Profiler / CPU Profiler / Hitches**: profile reproducible hangs
- **os_signpost** and `OSSignposter`: mark intervals for Instruments
- **MetricKit** hang diagnostics: production hang detection (see
`metrickit` skill for `MXHangDiagnostic`)
```swift
import os
let signposter = OSSignposter(subsystem: "com.example.app", category: "DataLoad")
func loadData() async {
let state = signposter.beginInterval("loadData")
let result = await fetchFromNetwork()
signposter.endInterval("loadData", state)
process(result)
}
```
### Using the Time Profiler
1. Product > Profile (Cmd+I) to launch Instruments.
2. Select the **Time Profiler** template.
3. Record while reproducing the slow interaction.
4. Focus on the main thread — sort by "Weight" to find hot paths.
5. Check "Hide System Libraries" to see only your code.
6. Double-click a heavy frame to jump to source.
### Common Hang Causes
| Cause | Symptom | Fix |
|-------|---------|-----|
| Synchronous I/O on main thread | Network/file reads block UI | Move to `Task { }` or background actor |
| Lock contention | Main thread waiting on a lock held by backgrouRelated in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.