Printed on: June 27, 2025
Swift 6.2 comes with a number of high quality of life enhancements for concurrency. Certainly one of these options is the power to have actor-isolated conformances to protocols. One other characteristic is that your code will now run on the primary actor by default.
This does imply that generally, you’ll run into compiler errors. On this weblog submit, I’ll discover these errors, and how one can repair them whenever you do.
Earlier than we do, let’s briefly discuss actor-isolated protocol conformance to know what this characteristic is about.
Understanding actor-isolated protocol conformance
Protocols in Swift can require sure capabilities or properties to be nonisolated
. For instance, we are able to outline a protocol that requires a nonisolated var identify
like this:
protocol MyProtocol {
nonisolated var identify: String { get }
}
class MyModelType: MyProtocol {
var identify: String
init(identify: String) {
self.identify = identify
}
}
Our code won’t compile in the meanwhile with the next error:
Conformance of 'MyModelType' to protocol 'MyProtocol' crosses into fundamental actor-isolated code and might trigger knowledge races
In different phrases, our MyModelType
is remoted to the primary actor and our identify
protocol conformance isn’t. Which means that utilizing MyProtocol
and its identify
in a nonisolated
manner, can result in knowledge races as a result of identify
isn’t truly nonisolated
.
While you encounter an error like this you may have two choices:
- Embrace the
nonisolated
nature ofidentify
- Isolate your conformance to the primary actor
The primary resolution often implies that you don’t simply make your property nonisolated
, however you apply this to your complete kind:
nonisolated class MyModelType: MyProtocol {
// ...
}
This would possibly work however you’re now breaking out of fundamental actor isolation and probably opening your self as much as new knowledge races and compiler errors.
When your code runs on the primary actor by default, going nonisolated
is commonly not what you need; every thing else remains to be on fundamental so it is smart for MyModelType
to remain there too.
On this case, we are able to mark our MyProtocol
conformance as @MainActor
:
class MyModelType: @MainActor MyProtocol {
// ...
}
By doing this, MyModelType
conforms to my protocol however solely after we’re on the primary actor. This mechanically makes the nonisolated
requirement for identify
pointless as a result of we’re at all times going to be on the primary actor after we’re utilizing MyModelType
as a MyProtocol
.
That is extremely helpful in apps which might be fundamental actor by default since you don’t need your fundamental actor sorts to have nonisolated
properties or capabilities (often). So conforming to protocols on the primary actor makes a whole lot of sense on this case.
Now let’s take a look at some errors associated to this characteristic, we could? I initially encountered an error round my SwiftData code, so let’s begin there.
Fixing Primary actor-isolated conformance to ‘PersistentModel’ can’t be utilized in actor-isolated context
Let’s dig proper into an instance of what can occur whenever you’re utilizing SwiftData and a customized mannequin actor. The next mannequin and mannequin actor produce a compiler error that reads “Primary actor-isolated conformance of ‘Train’ to ‘PersistentModel’ can’t be utilized in actor-isolated context”:
@Mannequin
class Train {
var identify: String
var date: Date
init(identify: String, date: Date) {
self.identify = identify
self.date = date
}
}
@ModelActor
actor BackgroundActor {
func instance() {
// Name to fundamental actor-isolated initializer 'init(identify:date:)' in a synchronous actor-isolated context
let train = Train(identify: "Operating", date: Date())
// Primary actor-isolated conformance of 'Train' to 'PersistentModel' can't be utilized in actor-isolated context
modelContext.insert(train)
}
}
There’s truly a second error right here too as a result of we’re calling the initializer for train from our BackgroundActor
and the init
for our Train
is remoted to the primary actor by default.
Fixing our drawback on this case implies that we have to enable Train
to be created and used from non-main actor contexts. To do that, we are able to mark the SwiftData mannequin as nonisolated
:
@Mannequin
nonisolated class Train {
var identify: String
var date: Date
init(identify: String, date: Date) {
self.identify = identify
self.date = date
}
}
Doing it will make each the init
and our conformance to PersistentModel
nonisolated
which implies we’re free to make use of Train
from non-main actor contexts.
Observe that this does not imply that Train
can safely be handed from one actor or isolation context to the opposite. It simply implies that we’re free to create and use Train
situations away from the primary actor.
Not each app will want this or encounter this, particularly whenever you’re operating code on the primary actor by default. In case you do encounter this drawback for SwiftData fashions, it’s best to in all probability isolate the problematic are to the primary actor until you particularly created a mannequin actor within the background.
Let’s check out a second error that, so far as I’ve seen is fairly frequent proper now within the Xcode 26 beta; utilizing Codable
objects with default actor isolation.
Fixing Conformance of protocol ‘Encodable’ crosses into fundamental actor-isolated code and might trigger knowledge races
This error is kind of attention-grabbing and I ponder whether it’s one thing Apple can and may repair through the beta cycle. That mentioned, as of Beta 2 you would possibly run into this error for fashions that conform to Codable
. Let’s take a look at a easy mannequin:
struct Pattern: Codable {
var identify: String
}
This mannequin has two compiler errors:
- Round reference
- Conformance of ‘Pattern’ to protocol ‘Encodable’ crosses into fundamental actor-isolated code and might trigger knowledge races
I’m not precisely positive why we’re seeing the primary error. I believe it is a bug as a result of it is unnecessary to me in the meanwhile.
The second error says that our Encodable
conformance “crossed into fundamental actor-isolated code”. In case you dig a bit deeper, you’ll see the next error as a proof for this: “Primary actor-isolated occasion methodology ‘encode(to:)’ can not fulfill nonisolated requirement”.
In different phrases, our protocol conformance provides a fundamental actor remoted implementation of encode(to:)
whereas the protocol requires this methodology to be non-isolated.
The rationale we’re seeing this error just isn’t completely clear to me however there appears to be a mismatch between our protocol conformance’s isolation and our Pattern
kind.
We will do one in all two issues right here; we are able to both make our mannequin nonisolated
or constrain our Codable
conformance to the primary actor.
nonisolated struct Pattern: Codable {
var identify: String
}
// or
struct Pattern: @MainActor Codable {
var identify: String
}
The previous will make it in order that every thing on our Pattern
is nonisolated
and can be utilized from any isolation context. The second possibility makes it in order that our Pattern
conforms to Codable
however solely on the primary actor:
func createSampleOnMain() {
// that is wonderful
let pattern = Pattern(identify: "Pattern Occasion")
let knowledge = strive? JSONEncoder().encode(pattern)
let decoded = strive? JSONDecoder().decode(Pattern.self, from: knowledge ?? Knowledge())
print(decoded)
}
nonisolated func createSampleFromNonIsolated() {
// this isn't wonderful
let pattern = Pattern(identify: "Pattern Occasion")
// Primary actor-isolated conformance of 'Pattern' to 'Encodable' can't be utilized in nonisolated context
let knowledge = strive? JSONEncoder().encode(pattern)
// Primary actor-isolated conformance of 'Pattern' to 'Decodable' can't be utilized in nonisolated context
let decoded = strive? JSONDecoder().decode(Pattern.self, from: knowledge ?? Knowledge())
print(decoded)
}
So typically talking, you don’t need your protocol conformance to be remoted to the primary actor to your Codable
fashions in the event you’re decoding them on a background thread. In case your fashions are comparatively small, it’s seemingly completely acceptable so that you can be decoding and encoding on the primary actor. These operations ought to be quick sufficient normally, and sticking with fundamental actor code makes your program simpler to cause about.
One of the best resolution will rely in your app, your constraints, and your necessities. All the time measure your assumptions when potential and keep on with options that give you the results you want; don’t introduce concurrency “simply to make certain”. In case you discover that your app advantages from decoding knowledge on a background thread, the answer for you is to mark your kind as nonisolated
; in the event you discover no direct advantages from background decoding and encoding in your app it’s best to constrain your conformance to @MainActor
.
In case you’ve carried out a customized encoding or decoding technique, you is perhaps operating into a distinct error…
Conformance of ‘CodingKeys’ to protocol ‘CodingKey’ crosses into fundamental actor-isolated code and might trigger knowledge races
Now, this one is a bit trickier. When we’ve a customized encoder or decoder, we would additionally need to present a CodingKeys
enum:
struct Pattern: @MainActor Decodable {
var identify: String
// Conformance of 'Pattern.CodingKeys' to protocol 'CodingKey' crosses into fundamental actor-isolated code and might trigger knowledge races
enum CodingKeys: CodingKey {
case identify
}
init(from decoder: any Decoder) throws {
let container = strive decoder.container(keyedBy: CodingKeys.self)
self.identify = strive container.decode(String.self, forKey: .identify)
}
}
Sadly, this code produces an error. Our conformance to CodingKey
crosses into fundamental actor remoted code and which may trigger knowledge races. Often this could imply that we are able to constraint our conformance to the primary actor and this could remedy our concern:
// Primary actor-isolated conformance of 'Pattern.CodingKeys' to 'CustomDebugStringConvertible' can not fulfill conformance requirement for a 'Sendable' kind parameter 'Self'
enum CodingKeys: @MainActor CodingKey {
case identify
}
This sadly doesn’t work as a result of CodingKeys
requires us to be CustomDebugStringConvertable
which requires a Sendable
Self
.
Marking our conformance to fundamental actor ought to imply that each CodingKeys
and CodingKey
are Sendable
however as a result of the CustomDebugStringConvertible
is outlined on CodingKey
I believe our @MainActor
isolation doesn’t carry over.
This may additionally be a tough edge or bug within the beta; I’m undecided.
That mentioned, we are able to repair this error by making our CodingKeys
nonisolated
:
struct Pattern: @MainActor Decodable {
var identify: String
nonisolated enum CodingKeys: CodingKey {
case identify
}
init(from decoder: any Decoder) throws {
let container = strive decoder.container(keyedBy: CodingKeys.self)
self.identify = strive container.decode(String.self, forKey: .identify)
}
}
This code works completely wonderful each when Pattern
is nonisolated
and when Decodable
is remoted to the primary actor.
Each this concern and the earlier one really feel like compiler errors, so if these get resolved throughout Xcode 26’s beta cycle I’ll be certain that to return again and replace this text.
In case you’ve encountered errors associated to actor-isolated protocol conformance your self, I’d love to listen to about them. It’s an attention-grabbing characteristic and I’m attempting to determine how precisely it suits into the way in which I write code.