axiom-swift-modern
Modern Swift Idioms
Purpose
Claude frequently generates outdated Swift patterns from its training data. This skill corrects the most common ones — patterns that compile fine but use legacy APIs when modern equivalents are clearer, more efficient, or more correct.
Philosophy: "Don't repeat what LLMs already know — focus on edge cases, surprises, soft deprecations." (Paul Hudson)
Modern API Replacements
| Old Pattern | Modern Swift | Since | Why |
|---|---|---|---|
Date() |
Date.now |
5.6 | Clearer intent |
filter { }.count |
count(where:) |
5.0 | Single pass, no intermediate allocation |
replacingOccurrences(of:with:) |
replacing(_:with:) |
5.7 | Swift native, no Foundation bridge |
CGFloat |
Double |
5.5 | Implicit bridging; exceptions: optionals, inout, ObjC-bridged APIs |
Task.sleep(nanoseconds:) |
Task.sleep(for: .seconds(1)) |
5.7 | Type-safe Duration API |
DateFormatter() |
.formatted() / FormatStyle |
5.5 | No instance management, localizable by default |
String(format: "%.2f", val) |
val.formatted(.number.precision(.fractionLength(2))) |
5.5 | Type-safe, localized |
localizedCaseInsensitiveContains() |
localizedStandardContains() |
5.0 | Handles diacritics, ligatures, width variants |
"\(firstName) \(lastName)" |
PersonNameComponents with .formatted() |
5.5 | Respects locale name ordering |
"yyyy-MM-dd" with DateFormatter |
try Date(string, strategy: .iso8601) |
5.6 | Modern parsing (throws); use "y" not "yyyy" for display |
contains() on user input |
localizedStandardContains() |
5.0 | Required for correct text search/filtering |
Modern Syntax
| Old Pattern | Modern Swift | Since |
|---|---|---|
if let value = value { |
if let value { |
5.7 |
Explicit return in single-expression |
Omit return; if/switch are expressions |
5.9 |
Circle() in modifiers |
.circle (static member lookup) |
5.5 |
import UIKit alongside import SwiftUI |
Often not needed — SwiftUI re-exports most UIKit/AppKit types. Retain for UIKit-only APIs (UIApplication, etc.) |
5.5 |
Foundation Modernization
| Old Pattern | Modern Foundation | Since |
|---|---|---|
FileManager.default.urls(for: .documentDirectory, ...) |
URL.documentsDirectory |
5.7 |
url.appendingPathComponent("file") |
url.appending(path: "file") |
5.7 |
books.sorted { $0.author < $1.author } (repeated) |
Conform to Comparable, call .sorted() |
— |
"yyyy" in date format for display |
"y" — correct in all calendar systems |
— |
SwiftUI Convenience APIs Claude Misses
ContentUnavailableView.search(text: searchText)(iOS 17+) automatically includes the search term — no need to compose a custom stringLabeledContentin Forms (iOS 16+) provides consistent label alignment without manual HStack layoutconfirmationDialog()must attach to triggering UI — Liquid Glass morphing animations depend on the source element
Swift 6.3 Concurrency Posture
Write Swift 6.3-first code, not Swift 5-era code. These defaults apply to ALL new Swift code, not just when concurrency errors appear.
| Default | Rationale |
|---|---|
| Assume strict concurrency and MainActor default isolation for app/UI modules | Swift 6.3 language mode; Xcode 26+ default for new projects |
| Prefer async/await over GCD, DispatchGroup, and callback pyramids | GCD is a bridge pattern for legacy APIs, not default architecture |
Async does not mean background — use @concurrent (Swift 6.2+) to force off-main |
Async functions resume on the same actor they were called from |
Prefer structured concurrency (async let, TaskGroup) over unstructured Task {} |
Structured tasks propagate cancellation and errors automatically |
Do not use Task.detached unless there is a specific, stated reason |
Loses actor context, priority, and task-local values |
| Prefer Sendable structs/enums for data that crosses actor boundaries | Value types are inherently safe to share |
| Use actors only for truly shared mutable state across concurrency domains | Don't make every class an actor — UI code stays @MainActor |
Treat @unchecked Sendable, @preconcurrency, nonisolated(unsafe) as temporary bridge tools |
Each should have a removal ticket, not be permanent |
| Do not add escape hatches just to silence compiler errors | They hide data races that crash in production |
For detailed patterns, decision trees, and error-specific guidance, see axiom-swift-concurrency.
Common Claude Hallucinations
These patterns appear frequently in Claude-generated code:
- Creates
DateFormatterinstances inline — Use.formatted()orFormatStyleinstead. If a formatter must exist, make itstatic let. - Uses
DispatchQueue.main.async— Use@MainActororMainActor.run. GCD is a bridge pattern, not a default. - Uses
DispatchQueue.global().asyncfor background work — Use@concurrent(Swift 6.2+) or extract to an actor. - Uses
Task.detachedto "make it background" — Use@concurrent.Task.detachedloses actor context. - Uses
CGFloatfor SwiftUI parameters —Doubleworks everywhere since Swift 5.5 implicit bridging. - Generates
guard let x = x else— Useguard let x elseshorthand. - Returns explicitly in single-expression computed properties — Omit
return. - Spawns unstructured
Task {}in loops — UseTaskGroupfor dynamic parallel work. - Adds
@unchecked Sendableto silence warnings — Convert to actor or proper Sendable type.
Resources
Skills: axiom-swift-performance, axiom-swift-concurrency, axiom-swiftui-architecture
More from charleswiltgen/axiom
axiom-vision
Use when implementing ANY computer vision feature — image analysis, pose detection, person segmentation, subject lifting, text recognition, barcode scanning.
772axiom-networking
Use when implementing or debugging ANY network connection, API call, or socket. Covers URLSession, Network.framework, NetworkConnection, connection diagnostics.
360axiom-apple-docs
Use when ANY question involves Apple framework APIs, Swift compiler errors, or Xcode-bundled documentation. Covers Liquid Glass, Swift 6.2 concurrency, Foundation Models, SwiftData, StoreKit, 32 Swift compiler diagnostics.
352axiom-swiftdata
Use when working with SwiftData - @Model definitions, @Query in SwiftUI, @Relationship macros, ModelContext patterns, CloudKit integration, iOS 26+ features, and Swift 6 concurrency with @MainActor — Apple's native persistence framework
298axiom-swiftui-26-ref
Use when implementing iOS 26 SwiftUI features - covers Liquid Glass design system, performance improvements, @Animatable macro, 3D spatial layout, scene bridging, WebView/WebPage, AttributedString rich text editing, drag and drop enhancements, and visionOS integration for iOS 26+
283axiom-xcode-mcp
Use when connecting to Xcode via MCP, using xcrun mcpbridge, or working with ANY Xcode MCP tool (XcodeRead, BuildProject, RunTests, RenderPreview). Covers setup, tool reference, workflow patterns, troubleshooting.
278