axiom-swift-concurrency
Use when you see 'actor-isolated', 'Sendable', 'data race', '@MainActor' errors, or when asking 'why is this not thread safe', 'how do I use async/await', 'what is @MainActor for', 'my app is crashing with concurrency errors', 'how do I fix data races' - Swift 6 strict concurrency patterns with actor isolation and async/await
Install
mkdir -p .claude/skills/axiom-swift-concurrency && curl -L -o skill.zip "https://mcp.directory/api/skills/download/4997" && unzip -o skill.zip -d .claude/skills/axiom-swift-concurrency && rm skill.zipInstalls to .claude/skills/axiom-swift-concurrency
About this skill
Swift 6 Concurrency Guide
Purpose: Progressive journey from single-threaded to concurrent Swift code
Swift Version: Swift 6.0+, Swift 6.2+ for @concurrent
iOS Version: iOS 17+ (iOS 18.2+ for @concurrent)
Xcode: Xcode 16+ (Xcode 16.2+ for @concurrent)
Context: WWDC 2025-268 "Embracing Swift concurrency" - approachable path to data-race safety
When to Use This Skill
✅ Use this skill when:
- Starting a new project and deciding concurrency strategy
- Debugging Swift 6 concurrency errors (actor isolation, data races, Sendable warnings)
- Deciding when to introduce async/await vs concurrency
- Implementing
@MainActorclasses or async functions - Converting delegate callbacks to async-safe patterns
- Deciding between
@MainActor,nonisolated,@concurrent, or actor isolation - Resolving "Sending 'self' risks causing data races" errors
- Making types conform to
Sendable - Offloading CPU-intensive work to background threads
- UI feels unresponsive and profiling shows main thread bottleneck
❌ Do NOT use this skill for:
- General Swift syntax (use Swift documentation)
- SwiftUI-specific patterns (use
axiom-swiftui-debuggingoraxiom-swiftui-performance) - API-specific patterns (use API documentation)
Core Philosophy: Start Single-Threaded
Apple's Guidance (WWDC 2025-268): "Your apps should start by running all of their code on the main thread, and you can get really far with single-threaded code."
The Progressive Journey
Single-Threaded → Asynchronous → Concurrent → Actors
↓ ↓ ↓ ↓
Start here Hide latency Background Move data
(network) CPU work off main
When to advance:
- Stay single-threaded if UI is responsive and operations are fast
- Add async/await when high-latency operations (network, file I/O) block UI
- Add concurrency when CPU-intensive work (image processing, parsing) freezes UI
- Add actors when too much main actor code causes contention
Key insight: Concurrent code is more complex. Only introduce concurrency when profiling shows it's needed.
Step 1: Single-Threaded Code (Start Here)
All code runs on the main thread by default in Swift 6.
// ✅ Simple, single-threaded
class ImageModel {
var imageCache: [URL: Image] = [:]
func fetchAndDisplayImage(url: URL) throws {
let data = try Data(contentsOf: url) // Reads local file
let image = decodeImage(data)
view.displayImage(image)
}
func decodeImage(_ data: Data) -> Image {
// Decode image data
return Image()
}
}
Main Actor Mode (Xcode 26+):
- Enabled by default for new projects
- All code protected by
@MainActorunless explicitly marked otherwise - Access shared state safely without worrying about concurrent access
Build Setting (Xcode 26+):
Build Settings → Swift Compiler — Language
→ "Default Actor Isolation" = Main Actor
Build Settings → Swift Compiler — Upcoming Features
→ "Approachable Concurrency" = Yes
When this is enough: If all operations are fast (<16ms for 60fps), stay single-threaded!
Step 2: Asynchronous Tasks (Hide Latency)
Add async/await when waiting on data (network, file I/O) would freeze UI.
Problem: Network Access Blocks UI
// ❌ Blocks main thread until network completes
func fetchAndDisplayImage(url: URL) throws {
let (data, _) = try URLSession.shared.data(from: url) // ❌ Freezes UI!
let image = decodeImage(data)
view.displayImage(image)
}
Solution: Async/Await
// ✅ Suspends without blocking main thread
func fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url) // ✅ Suspends here
let image = decodeImage(data) // ✅ Resumes here when data arrives
view.displayImage(image)
}
What happens:
- Function starts on main thread
awaitsuspends function without blocking main thread- URLSession fetches data on background thread (library handles this)
- Function resumes on main thread when data arrives
- UI stays responsive the entire time
Task Creation
Create tasks in response to user events:
class ImageModel {
var url: URL = URL(string: "https://swift.org")!
func onTapEvent() {
Task { // ✅ Create task for user action
do {
try await fetchAndDisplayImage(url: url)
} catch {
displayError(error)
}
}
}
}
Task Interleaving (Important Concept)
Multiple async tasks can run on the same thread by taking turns:
Task 1: [Fetch Image] → (suspend) → [Decode] → [Display]
Task 2: [Fetch News] → (suspend) → [Display News]
Main Thread Timeline:
[Fetch Image] → [Fetch News] → [Decode Image] → [Display Image] → [Display News]
Benefits:
- Main thread never sits idle
- Tasks make progress as soon as possible
- No concurrency yet—still single-threaded!
When to use tasks:
- High-latency operations (network, file I/O)
- Library APIs handle background work for you (URLSession, FileManager)
- Your own code stays on main thread
Step 3: Concurrent Code (Background Threads)
Add concurrency when CPU-intensive work blocks UI.
Problem: Decoding Blocks UI
Profiling shows decodeImage() takes 200ms, causing UI glitches:
func fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
let image = decodeImage(data) // ❌ 200ms on main thread!
view.displayImage(image)
}
Solution 1: @concurrent Attribute (Swift 6.2+)
Forces function to always run on background thread:
func fetchAndDisplayImage(url: URL) async throws {
let (data, _) = try await URLSession.shared.data(from: url)
let image = await decodeImage(data) // ✅ Runs on background thread
view.displayImage(image)
}
@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ Always runs on background thread pool
// Good for: image processing, file I/O, parsing
return Image()
}
What @concurrent does:
- Function always switches to background thread pool
- Compiler highlights main actor data access (shows what you need to fix)
- Cannot access
@MainActorproperties withoutawait
Requirements: Swift 6.2, Xcode 16.2+, iOS 18.2+
Solution 2: nonisolated (Library APIs)
If providing a general-purpose API, use nonisolated instead:
// ✅ Stays on caller's actor
nonisolated
func decodeImage(_ data: Data) -> Image {
// Runs on whatever actor called it
// Main actor → stays on main actor
// Background → stays on background
return Image()
}
When to use nonisolated:
- Library APIs where caller decides where work happens
- Small operations that might be OK on main thread
- General-purpose code used in many contexts
When to use @concurrent:
- Operations that should always run on background (image processing, parsing)
- Performance-critical work that shouldn't block UI
Breaking Ties to Main Actor
When you mark a function @concurrent, compiler shows main actor access:
@MainActor
class ImageModel {
var cachedImage: [URL: Image] = [:] // Main actor data
@concurrent
func decodeImage(_ data: Data, at url: URL) async -> Image {
if let image = cachedImage[url] { // ❌ Error: main actor access!
return image
}
// decode...
}
}
Strategy 1: Move to caller (keep work synchronous):
func fetchAndDisplayImage(url: URL) async throws {
// ✅ Check cache on main actor BEFORE async work
if let image = cachedImage[url] {
view.displayImage(image)
return
}
let (data, _) = try await URLSession.shared.data(from: url)
let image = await decodeImage(data) // No URL needed now
view.displayImage(image)
}
@concurrent
func decodeImage(_ data: Data) async -> Image {
// ✅ No main actor access needed
return Image()
}
Strategy 2: Use await (access main actor asynchronously):
@concurrent
func decodeImage(_ data: Data, at url: URL) async -> Image {
// ✅ Await to access main actor data
if let image = await cachedImage[url] {
return image
}
// decode...
}
Strategy 3: Make nonisolated (if doesn't need actor):
nonisolated
func decodeImage(_ data: Data) -> Image {
// ✅ No actor isolation, can call from anywhere
return Image()
}
Concurrent Thread Pool
When work runs on background:
Main Thread: [UI] → (suspend) → [UI Update]
↓
Background Pool: [Task A] → [Task B] → [Task A resumes]
Thread 1 Thread 2 Thread 3
Key points:
- System manages thread pool size (1-2 threads on Watch, many on Mac)
- Task can resume on different thread than it started
- You never specify which thread—system optimizes automatically
Step 4: Actors (Move Data Off Main Thread)
Add actors when too much code runs on main actor causing contention.
Problem: Main Actor Contention
@MainActor
class ImageModel {
var cachedImage: [URL: Image] = [:]
let networkManager: NetworkManager = NetworkManager() // ❌ Also @MainActor
func fetchAndDisplayImage(url: URL) async throws {
// ✅ Background work...
let connection = await networkManager.openConnection(for: url) // ❌ Hops to main!
let data = try await connection.data(from: url)
await networkManager.closeConnection(connection, for: url) // ❌ Hops to main!
let image = await decodeImage(data)
view.displayImage(image)
}
}
Issue: Background task keeps hopping to main actor for network manager access.
Solution: Network Manager Actor
// ✅ Move network state off main actor
actor NetworkManager {
---
*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 serversLogfire is a data observability platform for querying, analyzing, and monitoring OpenTelemetry traces, errors, and metri
Analyze Perfetto traces easily with Perfetto Trace Analyzer: turn natural language into actionable trace analysis insigh
Integrate Dynatrace, a leading data observability platform and APM tool, to monitor metrics, security, and network perfo
Alibaba Cloud Observability offers cloud based network monitoring and cloud monitoring solutions for application perform
Rtfmbro is an MCP server for config management tools—get real-time, version-specific docs from GitHub for Python, Node.j
Dynatrace Managed MCP Server delivers AI-driven access to self-hosted monitoring and observability platform, AIOps insig
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.