Revealed on: August 21, 2024
When you begin migrating to the Swift 6 language mode, you will probably activate strict concurrency first. As soon as you’ve got performed this there will likely be a number of warings and errors that you’re going to encounter and these errors will be complicated at occasions.
I am going to begin by saying that having a strong understanding of actors, sendable, and information races is a big benefit if you wish to undertake the Swift 6 language mode. Just about all the warnings you will get in strict concurrency mode will let you know about potential points associated to operating code concurrently. For an in-depth understanding of actors, sendability and information races I extremely advocate that you just check out my Swift Concurrency course which is able to get you entry to a sequence of movies, workouts, and my Sensible Swift Concurrency guide with a single buy.
WIth that out of the way in which, let’s check out the next warning that you just may encounter in your venture:
Job-isolated worth of sort ‘() async -> Void’ handed as a strongly transferred parameter
Once I first encountered the error above, I used to be puzzled. The code that made this occur wasn’t all that unusual and I had no concept what might be improper right here.
Let us take a look at an instance of the code that might make this error present up:
var myArray = [1, 2, 3]
await withTaskGroup(of: Void.self) { group in
for _ in 0..<10 {
// Job-isolated worth of sort '() async -> Void' handed as a strongly transferred parameter; later accesses may race;
group.addTask {
myArray.append(Int.random(in: 0..<10))
}
}
}
The issue above can even happen if you create an unstructured job with Job
or a indifferent job with Job.indifferent
. The error and the rationale for the error showing are the identical for all instances, however what precisely is improper within the code above?
Sadly, the compiler is not of a lot assist right here so we’ll have to determine this one out on our personal…
In each case that I’ve seen for this particular error, the duty that we create (whether or not it is a baby job, unstructured job or a indifferent job) captures a non-sendable object. To study extra about sendable, check out my submit that explains Sendable and @Sendable closures.
So whereas the compiler error is extraordinarily exhausting to learn and perceive, the rationale for it showing is definitely comparatively easy. We have got a powerful seize to one thing that is not Sendable
within a job that may run concurrently with different work. The result’s a attainable information race.
The repair can typically be comparatively easy for those who’re capable of make the captured sort sendable or an actor. Within the case of the code above that might be difficult; myArray
is an array of Int
which signifies that we’re already as sendable as we might be. However as a result of the array is mutable, there’s an opportunity that we’ll race.
There are a number of attainable fixes on this case. One among them is to mutate the array exterior of the kid duties by having baby duties produce numbers after which iterating over the duty group:
var myArray = [1, 2, 3]
await withTaskGroup(of: Int.self) { group in
for _ in 0..<10 {
group.addTask {
// Job-isolated worth of sort '() async -> Void' handed as a strongly transferred parameter; later accesses may race;
return (myArray.first ?? 2) * 2
}
}
for await worth in group {
myArray.append(worth)
}
}
Sadly, the above nonetheless produces an error…
The explanation for that’s that myArray
remains to be being accessed from inside a toddler job. In order that signifies that whereas a toddler job is studying, our async for loop might be writing after which we now have an information race.
To repair that we have to make a replica of myArray
within the baby job’s seize record like this:
group.addTask { [myArray] in
return (myArray.first ?? 2) * 2
}
With that change in place, the code compiles and runs accurately.
Sadly, Job-isolated worth of sort '() async -> Void' handed as a strongly transferred parameter
is a really powerful to learn error with no single repair. What this error tells you although, is that you just’re accessing or capturing a worth that is not sendable or secure to be accessed concurrently. Fixes for this might be:
- To make the captured object an actor
- To make the captured object sendable
- To make a replica of the item
- To seize properties on the item exterior of your job
- To rethink your method utterly (that is not often wanted)
As with many different strict concurrency associated points, fixing this error will rely in your skill to investigate the issue, and your understanding of actors and sendable. These are subjects that it’s best to attempt to perceive pretty much as good as you’ll be able to earlier than you try to migrate to Swift 6.