Swift 6.2 isn't a new type-system feature dump — it's a course correction on concurrency. After two years of teams either fighting the Swift 6 strict-concurrency checker or opting out of it entirely, this release makes the ergonomics of the common case — a UI-heavy app target where most code should just run on the main actor — the default, and makes going concurrent an explicit, opt-in decision instead of the other way around.
#Approachable Concurrency: default actor isolation per module
You can now set a target's default isolation to @MainActor instead of nonisolated, so a typical app target stops requiring @MainActor annotations sprinkled across every view model and helper type. You opt in per target in Package.swift.
swiftSettings: [.defaultIsolation(MainActor.self)]
This is the single biggest ergonomics change in the release for application code. Set it on app and feature targets; leave shared library targets on the concurrent-by-default behavior since consumers shouldn't inherit your UI assumptions.
#@concurrent: explicit opt-out to background execution
With a target defaulting to @MainActor, you need a clear way to say "this specific function should run off the main actor." That's @concurrent.
@concurrent
func decodeThumbnails(from data: [Data]) async -> [CGImage] {
[]
}
Use it on the handful of functions doing real CPU work — image decoding, parsing, hashing — that would otherwise block the main actor now that isolation is inherited by default rather than escaped by default.
#nonisolated functions now run on the caller's actor
Before 6.2, a plain nonisolated function called from a @MainActor context would hop to the concurrent executor even if the function did nothing that needed it — a common source of surprise await suspension points and subtle ordering bugs. In 6.2, a nonisolated async function runs on whatever actor called it by default, and only actually leaves that actor when it hits a genuine suspension point.
nonisolated func formatted(_ value: Double) -> String {
String(format: "%.2f", value)
}
Calling this from a view's @MainActor context no longer introduces an unnecessary executor hop. You still get @concurrent for the cases where you deliberately want off-actor work.
#InlineArray: fixed-size, stack-friendly arrays
InlineArray gives you a fixed-capacity array type whose size is part of its generic signature, stored inline rather than on the heap — useful for small, hot-path buffers where Array's heap allocation and reference counting are pure overhead.
var scores: InlineArray<4, Int> = [10, 20, 30, 40]
This is a narrow tool: reach for it in performance-sensitive, fixed-size contexts (parsers, codec buffers, fixed-length records), not as a general Array replacement.
#Raw identifiers: names with spaces
Backtick-escaped identifiers can now contain spaces and most punctuation, not just reserved keywords.
func `test the cart badge updates after adding an item`() {
}
This is aimed squarely at test function names. A descriptive backticked sentence in a test target is far more readable in a failure log than testCartBadgeUpdatesAfterAddingItem, and it costs nothing.
#What to adopt first
- Turn on
.defaultIsolation(MainActor.self)for your app and feature targets. This is where most of the "why is this still fighting the concurrency checker" pain lives, and the fix is a build setting, not a rewrite. - Audit your existing
nonisolatedfunctions once you upgrade — some code that was written defensively around the old hop-to-background behavior may no longer need the workarounds it has. - Add
@concurrentonly where you can name the reason: real CPU work that would otherwise stall the main actor. Don't apply it reflexively to "async" functions in general. - Adopt raw identifiers in test targets immediately — there's no downside and no migration cost.
- Leave
InlineArrayalone until you have a profiled hot path that needs it.
Deployment-target reality: none of this requires raising your app's iOS deployment target. These are compiler and language-mode features gated on the Swift 6.2 toolchain (Xcode 26), not on OS version — a project built with Xcode 26 in Swift 6.2 mode can still ship down to whatever iOS version it already supports. The thing that actually gates adoption is your team's Xcode version, not your users' devices.