Swift 6 appeared at WWDC 2024, and all of us rushed emigrate all our apps to it … nicely, not likely. We have been fairly proud of what we obtained at WWDC 2021 — Swift 5.5’s shiny new structured concurrency framework that helped us write secure code extra swiftly with async/await and actors. Swift 6 appeared to interrupt every part, and it felt like a good suggestion to attend some time.
One 12 months later, the migration path appears quite a bit smoother, with tons extra guideposts. Preserve studying to learn how a lot simpler it’s change into.
From Single-Thread to Concurrency
The purpose of Swift 6.2 concurrency is to simplify your app growth. It identifies three phases, the place you introduce concurrency explicitly, as and once you want it:
- Run every part on the principle thread: Begin with synchronous execution on the principle thread — if each operation is quick sufficient, your app’s UI received’t cling.
-
async/await: If it’s essential carry out a sluggish operation, create and
await
anasync
perform to do the work. This perform nonetheless runs on the principle thread, which interleaves its work with work from different duties, like responding to the person scrolling or tapping. For instance, in case your app must obtain information from a server, your asynchronous perform can do some setup thenawait
aURLSession
technique that runs on a background thread. At this level, your perform suspends, and the principle thread is free to do another work. When theURLSession
technique finishes, your perform is able to resume execution on the principle thread, often to supply some new information to show to the person. -
Concurrency: As you add extra asynchronous operations to the principle thread, your app’s UI would possibly change into much less responsive. Profile your app with Devices to search out efficiency issues and see in the event you can repair the issue — pace up the sluggish operation — with out concurrency. If not, introduce concurrency to maneuver that operation to a background thread and maybe use
async let
or process teams to run sub-tasks in parallel to reap the benefits of the a number of CPUs on the machine.
Isolation Domains
Swift 6.2 concurrency goals to remove information races, which occur when a course of on one thread modifies information whereas a course of on one other thread is accessing that information. Knowledge races can solely come up when your app has mutable objects, which is why Swift encourages you to make use of let
and worth sorts like struct
as a lot as doable.
The primary instruments to forestall information races are information isolation and isolation domains:
The essential function of an isolation area is the protection it supplies. Mutable state can solely be accessed from one isolation area at a time. You possibly can go mutable state from one isolation area to a different, however you’ll be able to by no means entry that state concurrently from a distinct area. This assure is validated by the compiler.
There are three classes of isolation area:
- Actor
- International actor
- Non-isolated
Actors shield their mutable objects by sustaining a serial queue for asynchronous requests coming from exterior their isolation area. A GlobalActor
should have a static property referred to as shared
that exposes an actor occasion that you simply make globally accessible — you don’t must inject the actor from one kind to a different, or into the SwiftUI atmosphere.
From Embracing Swift concurrency:
Nonisolated code could be very versatile, as a result of you’ll be able to name it from wherever: in the event you name it from the principle actor, it should keep on the principle actor. If you happen to name it from a background thread, it should keep on a background thread. This makes it an incredible default for general-purpose libraries.
Knowledge isolation ensures that non-isolated entities can’t entry the mutable state of different domains, so non-isolated capabilities and variables are at all times secure to entry from every other area.
Non-isolated is the default area at swift.org as a result of non-isolated code can’t mutate state protected in one other area. Nonetheless, new Xcode 26 initiatives could have MainActor
because the default isolation area, so each operation runs on the principle thread until you do one thing to maneuver work onto a background thread. The primary thread is serial, so mutable MainActor
objects could be accessed by at most one course of at a time.
Migrating to Swift 6.2
Swift.org Migration Information
The Swift Migration Information suggests a course of for migrating Swift 5 code to Swift 6. Whereas in Swift 5 language mode, incrementally allow Swift 6 checking in your mission’s Construct Settings. Allow these settings separately, in any order, and handle any points that come up:
Upcoming Options instructed by swift.org’s migration technique
In your mission’s Construct Settings, these are in Swift Compiler — Upcoming Options:
Upcoming Options ideas in Xcode Construct Settings
Word: I don’t see an actual match for GlobalConcurrency
, however it would possibly be Remoted International Variables.
Then, allow full concurency checking to activate the remaining information isolation checks. In Xcode, that is the Strict Concurrency Checking setting in Swift Compiler — Concurrency.
Xcode Construct Settings: Swift Compiler — Concurrency
Xcode 26 Default Settings
New Xcode 26 initiatives could have these default settings for the opposite two Swift Compiler — Concurrency settings:
- Approachable Concurrency: Sure: Permits a collection of upcoming options that make simpler to work with concurrency.
-
Default Actor Isolation: MainActor: Isolates code on the
MainActor
until you mark it as one thing else.
Enabling Approachable Concurrency permits a number of Upcoming Options, together with two of the swift.org’s migration technique ideas:
Upcoming Options that Approachable Concurrency permits
If this raises too many points, disable Approachable Concurrency and check out the swift.org migration technique as an alternative.
Getting Began
Use the Obtain Supplies button on the prime or backside of this text to obtain the starter mission, then open it in Xcode 26 (beta).
TheMet is a mission from SwiftUI Apprentice. It searches The Metropolitan Museum of Artwork, New York for objects matching the person’s question time period.
TheMet app: seek for Persimmon
TheMetService
has two strategies:
-
getObjectIDs(from:)
constructs the questionURL
and downloadsObjectID
values of artwork objects that match the question time period. -
getObject(from:)
fetches theObject
for a selectedObjectID
.
TheMetStore
instantiates TheMetService
and, in fetchObjects(for:)
calls getObjectIDs(from:)
then loops over the array of ObjectID
to populate its objects
array.
ContentView
instantiates TheMetStore
and calls its fetchObjects(from:)
technique when it seems and when the person enters a brand new question time period.
The pattern app makes use of this Thread
extension from SwiftLee’s put up Swift 6.2: A primary have a look at the way it’s altering Concurrency to point out which threads fetchObjects(for:)
, getObjectIDs(from:)
and getObject(from:)
are operating on.
nonisolated extension Thread {
/// A comfort technique to print out the present thread from an async technique.
/// This can be a workaround for compiler error:
/// Class property 'present' is unavailable from asynchronous contexts;
/// Thread.present can't be used from async contexts.
/// See: https://github.com/swiftlang/swift-corelibs-foundation/points/5139
public static var currentThread: Thread {
return Thread.present
}
}
On this tutorial, you’ll migrate TheMet to Swift 6.2 concurrency.
Construct and run and watch the console:
Retailer and Service strategies operating on background threads
TheMetStore
and TheMetService
strategies run solely on background threads, besides when fetchObjects(for:)
appends an object
to objects
, which ContentView
shows. Nonetheless, in Swift 6.2’s three-phase app growth course of, solely the URLSession
technique must run off the principle thread. You’ll quickly repair this!