- Published on
- 4 min read Intermediate
> What's New in Swift 6.3 and 6.4
Swift moved twice this cycle. Swift 6.3 arrived in the spring with the Xcode 26 point releases, and Swift 6.4 ships with Xcode 27 from WWDC 2026. Neither release is a Swift-6-sized earthquake, which after the strict concurrency migration is probably what everyone wanted. Instead you get three genuinely useful changes, two of which clean up long-standing awkwardness in async code. I've written a deeper dive on each, so this is the short version with links.
Module Selectors (Swift 6.3)
SE-0491 adds a dedicated :: operator for naming a declaration from a specific module. If a dependency exports a type that collides with one of yours, or two packages both define a Logger, you can now say exactly which one you mean:
import OSLog
import PulseLogging
let system = OSLog::Logger(subsystem: "com.example.app", category: "sync")
let network = PulseLogging::Logger()
Qualifying with the module name used to mostly work, except when your own module shadowed the name, and except in positions like macro attributes where it wasn't even expressible. The selector works in all of those spots. You won't need it often, but when you do, nothing else solves the problem. The full gotcha list is in my module selectors article.
Async defer (Swift 6.4)
The change I'm happiest about. SE-0493 lets you await inside a defer body in an async function. No new syntax to learn:
func syncMailbox() async throws {
let session = try await imap.connect()
defer { await session.logout() }
for folder in try await session.folders() {
try await ingest(folder)
}
}
Before 6.4, that cleanup either got threaded through every exit path by hand or dumped into a detached task from inside the defer, which silently dropped errors and gave you no guarantee the cleanup finished before the function's caller moved on. Now the function doesn't return until the deferred cleanup completes, in the right order, on every exit path. Details and the ordering rules are in the async defer article.
Task Cancellation Shields (Swift 6.4)
The partner feature. Once a task is cancelled, every cancellation check inside it reports cancelled forever, which is exactly wrong for cleanup that must run to completion. SE-0504 adds withTaskCancellationShield, which makes cancellation checks inside the block see an uncancelled task:
defer {
withTaskCancellationShield {
try? handle.synchronize()
try? handle.close()
}
}
The shield only affects what Task.isCancelled and Task.checkCancellation() report inside the scope. The task itself stays cancelled, and the real state is restored when the block returns. Combined with async defer, this finally gives Swift a complete story for "release this resource no matter what," without unstructured task tricks. I covered the overloads and the sharp edges in the cancellation shields article.
Adopting Them
Version support is the main thing to plan around. Module selectors need the Swift 6.3 compiler, which means Xcode 26.2 or later. The two concurrency features need Swift 6.4, which means Xcode 27. All three are source-level features of the compiler rather than OS APIs, so none of them require raising your deployment target, and there's no #available dance. Once your CI builds with Xcode 27, you can use them in code that still ships to iOS 16.
The quieter news is what didn't change: no new language mode, no new migration. If your project already builds under Swift 6 strict concurrency, 6.3 and 6.4 are drop-in compiler updates, and the diagnostics keep getting incrementally better. After the last few years, a boring pair of Swift releases feels like a feature in itself.
Sample Project
Want to see this code in action? Check out the complete sample project on GitHub:
The repository includes a working Xcode project with all the examples from this article, plus unit tests you can run to verify the behavior.
// Continue_Learning
Data Races Swift 6 Still Can't Catch
Swift 6's data-race safety is real, but it has blind spots. Here are the places the compiler can't see, and how to stop treating a clean build as proof your code is thread safe.
Async defer in Swift 6.4
SE-0493 finally lets you write defer { await cleanup() } in async functions, without spawning a detached task or threading cleanup logic through every return path.
Task Cancellation Shields in Swift 6.4
Swift 6.4's withTaskCancellationShield lets cleanup code run to completion even after a task has been cancelled, without spawning extra unstructured tasks.
// Stay Updated
Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.