Swift 6 has been accessible to us for the higher a part of a 12 months now, and increasingly groups are contemplating or migrating to the Swift 6 language mode. This sometimes entails making an attempt to activate the language mode or turning on strict concurrency, seeing a complete bunch of warnings or errors, after which deciding that at this time isn’t the day to proceed with this migration.
At the moment I want to suggest an method to how one can plan your migration in a approach that gained’t scare you out of making an attempt the migration earlier than you’ve even began.
Earlier than you undergo this whole publish anticipating me to inform you the right way to go to Swift 6 inside a matter of days or perhaps weeks, I am afraid I will should disappoint you.
Migrating to Swift 6, for lots of apps, goes to be a really gradual and prolonged course of and it is actually a course of that you do not wish to rush.
Taking an preliminary stock
Earlier than you begin to migrate your codebase, I might extremely suggest that you simply take stock of the state of your codebase. Which means it’s best to check out how modularized your codebase is, which dependencies you’ve got in your codebase, and possibly most significantly how a lot concurrency you’re actually utilizing proper now. Learn the way usually you’re explicitly, and purposefully you’re leaving the primary thread. And attempt to perceive how a lot of your code will run on the primary thread.
You also needs to take a look at your crew and determine how up-to-date your crew is, how snug they’re with Swift concurrency already. Ultimately, the whole crew will want to have the ability to work on and together with your Swift 6 codebase.
On a code degree, it is important to know how a lot concurrency you really want as a result of Swift concurrency is, by design, going to introduce loads of concurrency into your app the place possibly you do not really want all of that concurrency. That’s why it’s so vital so that you can determine the quantity of concurrency you’ll require beforehand by analyzing what you’ve got now.
For instance, when you have a view and you’ve got a view mannequin, and that view mannequin talks to a different layer, then in all probability you’re doing many of the work on the primary thread proper now.
When you hit your networking layer, your community calls will run elsewhere, and when your networking associated features invoke their callbacks, these will sometimes run on a background thread, and then you definately come again to the primary thread to replace your UI.
On this situation, you do not want loads of concurrency; actually, I might say that you do not want concurrency past what URLSession gives in any respect. So when you’re adopting Swift Concurrency, you’ll wish to perceive how one can construction your code to not go away the primary thread for each async name.
You may have already got adopted async-await, and that is utterly effective—it in all probability signifies that you do have extra concurrency than you really want. Each nonisolated async perform that you simply write will, by default, run on a background thread. You don’t all the time want this; you’ll most certainly wish to explicitly isolate a few of your work to the primary actor to forestall leveraging concurrency in locations the place it’s merely not benefitting you.
You may additionally wish to just be sure you perceive how dependent or how coupled your codebase is as a result of the extra coupling you’ve got and the much less abstractions and modularization you’ve got, the extra complexities you may run into. Understanding your codebase deeply is a prerequisite to transferring to Swift 6.
When you perceive your codebase, you may wish to take a look at modularizing. I might say that is the most suitable choice. It does make migrating a bit of bit simpler.
So let’s speak about modularization subsequent.
Modularizing your codebase
Once you migrate to Swift 6, you will discover that loads of objects in your code are being handed from one place to a different, and if you begin to introduce concurrency in a single a part of the code, you’re basically pressured emigrate something that is determined by that a part of your codebase.
Having a modularized codebase means that you would be able to take your codebase and migrate it over time. You’ll be able to transfer element by element, moderately than being pressured to maneuver all the things abruptly.
You should utilize options like @preconcurrency to be sure that your app can nonetheless use your Swift 6 modules with out working into every kind of isolation or sendability warnings till your app additionally opts in to strict concurrency.
When you do not wish to modularize your codebase otherwise you really feel your codebase is approach too small to be modularized, that is utterly effective. I am simply saying that the smaller your elements are, the better your migration goes to be.
As soon as you already know the state your codebase is in and you are feeling snug with how all the things is, it is time to activate strict concurrency checks.
Turning on strict concurrency checks
Earlier than you activate Swift 6 language mode, it is strongly recommended to activate strict concurrency checking for the modules that you simply wish to migrate. You are able to do this for each SPM and in Xcode in your app goal.
I might suggest to do that on a module by module foundation.
So if you wish to refactor your fashions bundle first, activate strict concurrency checks in your mannequin bundle, however not but in your app. Turning on strict concurrency for just one module permits you to work on that bundle with out forcing your app to decide into the entire sendability and isolation checks associated to the bundle you’re refactoring.
Having the ability to migrate one bundle at a time is tremendous helpful as a result of it makes all the things lots simpler to purpose about because you’re reasoning about smaller bits of your code.
Upon getting your strict concurrency checks turned on you are going to see a complete bunch of warnings for the packages and targets the place you’ve got enabled strict concurrency and you can begin fixing them. For instance, it’s doubtless that you will run into points like predominant actor remoted objects to sendable closures.
You may wish to just be sure you perceive these errors earlier than you proceed.
You wish to be sure that your entire warnings are resolved earlier than you activate Swift 6 language mode, and also you wish to just be sure you’ve received a extremely good sense of how your code is meant to work.
The toughest half in fixing your strict concurrency warnings is that making the compiler pleased generally simply is not sufficient. You may ceaselessly wish to just be sure you truly purpose in regards to the intent of your code moderately than simply making the compiler pleased.
Take into account the next code instance:
func loadPages() {
for web page in 0..
We’re iterating over an inventory of numbers and we’re making a bunch of community calls. These community calls occur concurrently and our perform does not anticipate all of them to finish. Now, the quickest method to migrate this over to Swift concurrency could be to write down an async perform and a for loop that appears like this:
func loadPages() async throws {
for web page in 0..
The that means of this code has now modified solely. We’re making community calls one after the other and the perform does not return till each name is full. If we do wish to introduce Swift concurrency right here and maintain the identical semantics we must create unstructured duties for each single community name or we might use a job group and kick off all our community calls in parallel that approach.
Utilizing a job group would change the way in which this perform works, as a result of the perform must anticipate the duty group to finish moderately than simply letting unstructured duties run. On this refactor, it’s essential to know what structured concurrency is and when it is sensible to create unstructured duties.
You are having to consider what the intent of the code is earlier than you migrate after which additionally how and if you wish to change that in your migration. If you wish to maintain all the things the identical, it is usually not sufficient to maintain the compiler pleased.
Whereas educating Groups about Swift Concurrency, I discovered it actually vital to know precisely which instruments you’ve got on the market and to consider how you have to be reasoning about your code.
As soon as you’ve got turned on Swift Concurrency checks, it is time to be sure that your whole crew is aware of what to do.
Making certain your crew has all of the data they want
I’ve seen a number of corporations try migrations to SwiftUI, Swift Knowledge, and Swift Concurrency. They usually take approaches the place a small crew does all of the legwork when it comes to exploring and studying these applied sciences earlier than the remainder of the crew is requested to study them too and to undertake them. Nevertheless, this usually means that there is a small crew within the corporate that you might contemplate to be consultants. They will have had entry to sources, they’re going to have had time to coach, and as soon as they provide you with the final large image of how issues needs to be performed, the remainder of the crew type of has to study on the job. Generally this works effectively, however usually this breaks down as a result of the remainder of the crew merely wants to completely perceive what they’re coping with earlier than they’ll successfully study.
So I all the time suggest if you wish to migrate over to Swift Concurrency have your crew enroll in certainly one of my workshops or use my books or my course or discover some other useful resource that may train the crew all the things they should know. It is actually not trivial to choose up Swift Concurrency, particularly not if you wish to go into strict concurrency mode. Writing async-await features is comparatively simple, however understanding what occurs is de facto what you want in case you’re planning emigrate and go all-in on concurrency.
As soon as you’ve got determined that you will go for Swift 6 and did you wish to degree up your crew’s concurrency abilities be sure you truly give everyone on the crew an opportunity to correctly study!
Migrating from the skin in
As soon as you’ve got began refactoring your packages and it is time to begin working in your app goal I discovered that it actually is sensible emigrate from the skin in. You may additionally work from the within out and ultimately, it actually is determined by the place you wish to begin. That mentioned, I usually like to begin within the view layer as soon as all of the back-end stuff is finished as a result of it helps me decide at which level within the app I wish to go away the primary actor (or when yo apply a predominant actor annotation to remain on the primary actor).
For instance, in case you’re utilizing MVVM and you’ve got a view mannequin that holds a bunch of features, the place ought to these features run?
That is the place the work that you simply did up entrance comes into play since you already know that within the outdated approach of doing issues the view mannequin would run its features on the primary thread. I might extremely suggest that you don’t change this. In case your view mannequin used to run on the primary thread which is just about normal, maintain it that approach.
You may wish to apply a predominant actor annotation to your view mannequin class.
This isn’t a nasty factor by any means, it isn’t a hack both. It is a approach so that you can be sure that you are not switching isolation contexts on a regular basis. You actually do not want a ton of concurrency in your app code.
So so that you can default your view fashions and possibly another objects in your code base to the primary actor merely makes loads of sense. When you begin migrating like this you will determine that you simply actually did not want that a lot concurrency which you already ought to know as a result of that is what you found out early on into course of.
That is additionally the place you begin to encounter warnings which can be associated to sendability and isolation contexts. When you begin to see these warnings and errors, you resolve that the mannequin ought to or should not be sendable relying on whether or not the change of isolation context that’s inflicting the warning is anticipated.
You’ll be able to resolve sendability issues with actors. That mentioned, making issues actors is normally not what you are searching for particularly when it is associated to fashions.
Nevertheless, if you’re coping with a reference kind that has mutable state, that is the place you may introduce actors. It’s all about determining whether or not you had been anticipating to make use of that kind in a number of isolation contexts.
Having to deeply purpose about each error and warning can generally really feel tedious as a result of it actually slows you down. You’ll be able to simply make one thing sendable, you might simply make one thing an actor, and it would not impression your code that a lot. However you’re introducing loads of complexity into your codebase if you’re introducing isolation contexts and if you’re introducing concurrency.
So once more, you actually wish to just be sure you restrict the quantity of concurrency in your app. You sometimes do not want loads of concurrency inside an software. I can not stress this sufficient.
Pitfalls, caveats, and risks
Migrating to Swift 6 positively comes with its risks and uncertainties. When you’re migrating all the things abruptly, you are going to be embarking on an enormous refactor that may contain touching nearly each single object in your code. When you introduce actors the place they actually should not belong, you instantly have all the things in your code turning into concurrent as a result of interacting with actors is an asynchronous proces.
When you did not observe the steps on this weblog publish, you are in all probability going to have asynchronous features everywhere, they usually could be members of courses or your view or anything. A few of your async features are going to be remoted to the primary actor, however most of them can be non-isolated by default, which signifies that they’ll run wherever. This additionally signifies that in case you move fashions or objects out of your view to your few mannequin to another place that you simply’re skipping isolation contexts on a regular basis. Generally that is utterly effective, and the compiler will determine that issues are literally secure, however in loads of instances, the compiler goes to complain about this, and you can be very annoyed about this as a result of you haven’t any concept what’s improper.
There’s additionally the matter of interacting with Apple’s code. Not all of Apple’s code is essentially Swift 6 appropriate or Swift 6 pleasant. So that you may end up having to write down workarounds for interacting with issues like a CLLocationManagerDelegate
or different objects that come from Apple’s frameworks. Generally it is trivial to know what to do when you totally perceive how isolation works, however loads of the occasions you are going to be left guessing about what makes essentially the most sense.
That is merely unavoidable, and we want Apple to work on their code and their annotations to be sure that we are able to undertake Swift 6 with full confidence.
On the similar time, Apple is Swift as a language and determining that Swift 6 is de facto not within the place the place they need it to be for normal adoption.
When you’re adopting Swift 6 proper now, there are some issues that may change down the road. It’s a must to be keen to cope with that. When you’re not keen to cope with that, I might suggest that you simply go for strict concurrency and do not go all-in on Swift 6 as a result of issues may change down the road and you do not wish to be doing a ton of labor that seems to be out of date. A pair variations of Swift down the road, and we’re in all probability speaking months, not years, earlier than this occurs.
In Abstract
General, I feel adopting Swift 6 is a big enterprise for many groups. If you have not began already and also you’re about to begin now, I might urge you to take it gradual – take it simple and just be sure you perceive what you are doing as a lot as potential each step of the way in which.
Swift concurrency is fairly difficult, and Apple remains to be actively engaged on bettering and altering it as a result of they’re nonetheless studying about issues which can be inflicting issues for individuals on a regular basis. So for that purpose, I am not even certain that migrating to Swift 6 needs to be certainly one of your main targets at this cut-off date.
Understanding all the things round Swift 6 I feel is extraordinarily helpful as a result of it does assist you to write down higher and safer code. Nevertheless, I do consider that sticking with the Swift 5 language mode and going for strict concurrency might be your most secure wager as a result of it permits you to write code that is probably not totally Swift 6 compliant however works utterly effective (a minimum of you possibly can nonetheless compile your undertaking even when you have a complete bunch of warnings).
I might like to know your ideas and progress on migrating to Swift 6. In my workshops I all the time hear actually cool tales about corporations which can be engaged on their migration and so when you have tales about your migration and your journey with Swift 6, I might love to listen to that.