axiom-hang-diagnostics
Use when app freezes, UI unresponsive, main thread blocked, watchdog termination, or diagnosing hang reports from Xcode Organizer or MetricKit
Install
mkdir -p .claude/skills/axiom-hang-diagnostics && curl -L -o skill.zip "https://mcp.directory/api/skills/download/6763" && unzip -o skill.zip -d .claude/skills/axiom-hang-diagnostics && rm skill.zipInstalls to .claude/skills/axiom-hang-diagnostics
About this skill
Hang Diagnostics
Systematic diagnosis and resolution of app hangs. A hang occurs when the main thread is blocked for more than 1 second, making the app unresponsive to user input.
Red Flags — Check This Skill When
| Symptom | This Skill Applies |
|---|---|
| App freezes briefly during use | Yes — likely hang |
| UI doesn't respond to touches | Yes — main thread blocked |
| "App not responding" system dialog | Yes — severe hang |
| Xcode Organizer shows hang diagnostics | Yes — field hang reports |
| MetricKit MXHangDiagnostic received | Yes — aggregated hang data |
| Animations stutter or skip | Maybe — could be hitch, not hang |
| App feels slow but responsive | No — performance issue, not hang |
What Is a Hang
A hang is when the main runloop cannot process events for more than 1 second. The user taps, but nothing happens.
User taps → Main thread busy/blocked → Event queued → 1+ second delay → HANG
Key distinction: The main thread handles ALL user input. If it's busy or blocked, the entire UI freezes.
Hang vs Hitch vs Lag
| Issue | Duration | User Experience | Tool |
|---|---|---|---|
| Hang | >1 second | App frozen, unresponsive | Time Profiler, System Trace |
| Hitch | 1-3 frames (16-50ms) | Animation stutters | Animation Hitches instrument |
| Lag | 100-500ms | Feels slow but responsive | Time Profiler |
This skill covers hangs. For hitches, see axiom-swiftui-performance. For general lag, see axiom-performance-profiling.
The Two Causes of Hangs
Every hang has one of two root causes:
1. Main Thread Busy
The main thread is doing work instead of processing events.
Subcategories:
| Type | Example | Fix |
|---|---|---|
| Proactive work | Pre-computing data user hasn't requested | Lazy initialization, compute on demand |
| Irrelevant work | Processing all notifications, not just relevant ones | Filter notifications, targeted observers |
| Suboptimal API | Using blocking API when async exists | Switch to async API |
2. Main Thread Blocked
The main thread is waiting for something else.
Subcategories:
| Type | Example | Fix |
|---|---|---|
| Synchronous IPC | Calling system service synchronously | Use async API variant |
| File I/O | Data(contentsOf:) on main thread | Move to background queue |
| Network | Synchronous URL request | Use URLSession async |
| Lock contention | Waiting for lock held by background thread | Reduce critical section, use actors |
| Semaphore/dispatch_sync | Blocking on background work | Restructure to async completion |
Decision Tree — Diagnosing Hangs
START: App hangs reported
│
├─→ Do you have hang diagnostics from Organizer or MetricKit?
│ │
│ ├─→ YES: Examine stack trace
│ │ │
│ │ ├─→ Stack shows your code running
│ │ │ → BUSY: Main thread doing work
│ │ │ → Profile with Time Profiler
│ │ │
│ │ └─→ Stack shows waiting (semaphore, lock, dispatch_sync)
│ │ → BLOCKED: Main thread waiting
│ │ → Profile with System Trace
│ │
│ └─→ NO: Can you reproduce?
│ │
│ ├─→ YES: Profile with Time Profiler first
│ │ │
│ │ ├─→ High CPU on main thread
│ │ │ → BUSY: Optimize the work
│ │ │
│ │ └─→ Low CPU, thread blocked
│ │ → Use System Trace to find what's blocking
│ │
│ └─→ NO: Enable MetricKit in app
│ → Wait for field reports
│ → Check Organizer > Hangs
Tool Selection
| Scenario | Primary Tool | Why |
|---|---|---|
| Reproduces locally | Time Profiler | See exactly what main thread is doing |
| Blocked thread suspected | System Trace | Shows thread state, lock contention |
| Field reports only | Xcode Organizer | Aggregated hang diagnostics |
| Want in-app data | MetricKit | MXHangDiagnostic with call stacks |
| Need precise timing | System Trace | Nanosecond-level thread analysis |
Time Profiler Workflow for Hangs
- Launch Instruments → Select Time Profiler template
- Record during hang → Reproduce the freeze
- Stop recording → Find the hang period in timeline
- Select hang region → Drag to select frozen timespan
- Examine call tree → Look for main thread work
What to look for:
- Functions with high "Self Time" on main thread
- Unexpectedly deep call stacks
- System calls that shouldn't be on main thread
System Trace Workflow for Blocked Hangs
- Launch Instruments → Select System Trace template
- Record during hang → Capture thread states
- Find main thread → Filter to main thread
- Look for red/orange → Blocked states
- Examine blocking reason → Lock, semaphore, IPC
Thread states:
- Running (blue): Executing code
- Preempted (orange): Runnable but not scheduled
- Blocked (red): Waiting for resource
Common Hang Patterns and Fixes
Pattern 1: Synchronous File I/O
Before (hangs):
// Main thread blocks on file read
func loadUserData() {
let data = try! Data(contentsOf: largeFileURL) // BLOCKS
processData(data)
}
After (async):
func loadUserData() {
Task.detached {
let data = try Data(contentsOf: largeFileURL)
await MainActor.run {
self.processData(data)
}
}
}
Pattern 2: Unfiltered Notification Observer
Before (processes all):
NotificationCenter.default.addObserver(
self,
selector: #selector(handleChange),
name: .NSManagedObjectContextObjectsDidChange,
object: nil // Receives ALL contexts
)
After (filtered):
NotificationCenter.default.addObserver(
self,
selector: #selector(handleChange),
name: .NSManagedObjectContextObjectsDidChange,
object: relevantContext // Only this context
)
Pattern 3: Expensive Formatter Creation
Before (creates each time):
func formatDate(_ date: Date) -> String {
let formatter = DateFormatter() // EXPENSIVE
formatter.dateStyle = .medium
return formatter.string(from: date)
}
After (cached):
private static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
func formatDate(_ date: Date) -> String {
Self.dateFormatter.string(from: date)
}
Pattern 4: dispatch_sync to Main Thread
Before (deadlock risk):
// From background thread
DispatchQueue.main.sync { // BLOCKS if main is blocked
updateUI()
}
After (async):
DispatchQueue.main.async {
self.updateUI()
}
Pattern 5: Semaphore for Async Result
Before (blocks main thread):
func fetchDataSync() -> Data {
let semaphore = DispatchSemaphore(value: 0)
var result: Data?
URLSession.shared.dataTask(with: url) { data, _, _ in
result = data
semaphore.signal()
}.resume()
semaphore.wait() // BLOCKS MAIN THREAD
return result!
}
After (async/await):
func fetchData() async throws -> Data {
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
Pattern 6: Lock Contention
Before (shared lock):
class DataManager {
private let lock = NSLock()
private var cache: [String: Data] = [:]
func getData(for key: String) -> Data? {
lock.lock() // Main thread waits for background
defer { lock.unlock() }
return cache[key]
}
}
After (actor):
actor DataManager {
private var cache: [String: Data] = [:]
func getData(for key: String) -> Data? {
cache[key] // Actor serializes access safely
}
}
Pattern 7: App Launch Hang (Watchdog)
Before (too much work):
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
loadAllUserData() // Expensive
setupAnalytics() // Network calls
precomputeLayouts() // CPU intensive
return true
}
After (deferred):
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Only essential setup
setupMinimalUI()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Defer non-essential work
Task {
await loadUserDataInBackground()
}
}
Pattern 8: Image Processing on Main Thread
Before (blocks UI):
func processImage(_ image: UIImage) {
let filtered = applyExpensiveFilter(image) // BLOCKS
imageView.image = filtered
}
After (background processing):
func processImage(_ image: UIImage) {
imageView.image = placeholder
Task.detached(priority: .userInitiated) {
let filtered = applyExpensiveFilter(image)
await MainActor.run {
self.imageView.image = filtered
}
}
}
Xcode Organizer Hang Diagnostics
Window > Organizer > Select App > Hangs
The Organizer shows aggregated hang data from users who opted into sharing diagnostics.
Reading the report:
- Hang Rate: Hangs per day per device
- Call Stack: Where the hang occurred
- Device/OS breakdown: Which configurations affected
Interpreting call stacks:
- Your code at top: Main thread busy with your work
- System API at top: You called blocking API on main thread
- pthread_mutex/semaphore: Lock contention or explicit waiting
MetricKit Hang Diagnostics
Adopt MetricKit to receive hang diagnostics in your app:
import MetricKit
clas
---
*Content truncated.*
More by CharlesWiltgen
View all skills by CharlesWiltgen →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversAccess Intercom data securely via a remote MCP server with authenticated connections for AI tools and live updates.
Boost productivity with Task Master: an AI-powered tool for project management and agile development workflows, integrat
Supercharge browser tasks with Browser MCP—AI-driven, local browser automation for powerful, private testing. Inspired b
Boost Postgres performance with Postgres MCP Pro—AI-driven index tuning, health checks, and safe, intelligent SQL optimi
Powerful MCP server for Slack with advanced API, message fetching, webhooks, and enterprise features. Robust Slack data
Transform Figma designs into high-quality code with AI. Seamless figma to code and figma to html workflows for efficient
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.