All posts
Swift Concurrency iOS Swift 6

What's New in Swift 6.2: Concurrency Gets Friendlier

Swift 6 was a landmark release, but its strict concurrency model also caused a lot of friction. Many teams hit hundreds of compiler errors when enabling Swift 6 mode, even in codebases that worked perfectly fine. Swift 6.2 addresses this head-on.

The Big Change: Strict Concurrency Is Now Opt-In

In Swift 6.0 and 6.1, strict concurrency checking was on by default in Swift 6 language mode. Swift 6.2 flips this: you can now enable it selectively with the new -strict-concurrency=complete flag, while the default becomes a softer checking mode that catches only clear data races.

This is a pragmatic decision. Apple acknowledged that the migration cost was too high for many projects, and that some of the original rules were overly conservative.

Default Main Actor Isolation

One of the most impactful changes in 6.2 is that top-level code and types in modules marked with @MainActor now inherit that isolation automatically.

Before 6.2, you often had to annotate every view model, delegate, and helper with @MainActor explicitly:

// Swift 6.1 — explicit everywhere
@MainActor
class ProfileViewModel: ObservableObject {
    var name: String = ""
}

With 6.2, if your module declares @MainActor as the default isolation, you get it for free on all types unless you opt out:

// Swift 6.2 — inherited from module default
class ProfileViewModel: ObservableObject {
    var name: String = ""  // implicitly @MainActor
}

// Opt out explicitly when needed
nonisolated func fetchFromBackground() async -> String { ... }

This dramatically reduces boilerplate for UI-heavy codebases.

The sending Parameter Attribute

Swift 6.2 formalizes the sending attribute for function parameters and return values. It expresses that ownership of a value is being transferred across concurrency boundaries — without requiring the type to be Sendable.

func process(data: sending Data) async {
    // data is safe to use here, even if Data weren't Sendable
}

This is particularly useful for types you don’t own (from third-party SDKs) that you know are safe to pass across actors in practice.

Improved nonisolated(unsafe)

The nonisolated(unsafe) annotation existed in Swift 6.0 but had rough edges. In 6.2 it’s been refined: the compiler is smarter about when to require it and the error messages are clearer.

Use it when you have a stored property that you’re certain is safe to access from any isolation context, but can’t prove it statically:

class Cache {
    nonisolated(unsafe) var store: [String: Any] = [:]
}

Should You Migrate Now?

If you’re on Swift 6.0 or 6.1 and struggling with concurrency warnings, Swift 6.2 is worth the upgrade. The combination of default main actor isolation and opt-in strict checking makes the model much more approachable without sacrificing safety where it matters.

Start by adding -strict-concurrency=minimal to your build settings, fix the remaining warnings incrementally, then bump to complete when you’re ready. The journey is shorter than it was a year ago.