Revealed 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 principle actor by default.
This does imply that typically, you’ll run into compiler errors. On this weblog submit, I’ll discover these errors, and how one can repair them while you do.
Earlier than we do, let’s briefly discuss actor-isolated protocol conformance to grasp 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 will outline a protocol that requires a nonisolated var title
like this:
protocol MyProtocol {
nonisolated var title: String { get }
}
class MyModelType: MyProtocol {
var title: String
init(title: String) {
self.title = title
}
}
Our code is not going to compile in the intervening time with the next error:
Conformance of 'MyModelType' to protocol 'MyProtocol' crosses into principal actor-isolated code and might trigger information races
In different phrases, our MyModelType
is remoted to the principle actor and our title
protocol conformance isn’t. Which means that utilizing MyProtocol
and its title
in a nonisolated
manner, can result in information races as a result of title
isn’t really nonisolated
.
Whenever you encounter an error like this you may have two choices:
- Embrace the
nonisolated
nature oftitle
- Isolate your conformance to the principle actor
The primary answer often signifies that you don’t simply make your property nonisolated
, however you apply this to your whole sort:
nonisolated class MyModelType: MyProtocol {
// ...
}
This may work however you’re now breaking out of principal actor isolation and probably opening your self as much as new information races and compiler errors.
When your code runs on the principle actor by default, going nonisolated
is usually not what you need; every thing else remains to be on principal so it is smart for MyModelType
to remain there too.
On this case, we will 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 principle actor. This robotically makes the nonisolated
requirement for title
pointless as a result of we’re at all times going to be on the principle actor after we’re utilizing MyModelType
as a MyProtocol
.
That is extremely helpful in apps which are principal actor by default since you don’t need your principal actor sorts to have nonisolated
properties or capabilities (often). So conforming to protocols on the principle actor makes plenty of sense on this case.
Now let’s have a look at some errors associated to this characteristic, lets? I initially encountered an error round my SwiftData code, so let’s begin there.
Fixing Most important actor-isolated conformance to ‘PersistentModel’ can’t be utilized in actor-isolated context
Let’s dig proper into an instance of what can occur while you’re utilizing SwiftData and a customized mannequin actor. The next mannequin and mannequin actor produce a compiler error that reads “Most important actor-isolated conformance of ‘Train’ to ‘PersistentModel’ can’t be utilized in actor-isolated context”:
@Mannequin
class Train {
var title: String
var date: Date
init(title: String, date: Date) {
self.title = title
self.date = date
}
}
@ModelActor
actor BackgroundActor {
func instance() {
// Name to principal actor-isolated initializer 'init(title:date:)' in a synchronous actor-isolated context
let train = Train(title: "Operating", date: Date())
// Most important actor-isolated conformance of 'Train' to 'PersistentModel' can't be utilized in actor-isolated context
modelContext.insert(train)
}
}
There’s really 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 principle actor by default.
Fixing our downside on this case signifies that we have to enable Train
to be created and used from non-main actor contexts. To do that, we will mark the SwiftData mannequin as nonisolated
:
@Mannequin
nonisolated class Train {
var title: String
var date: Date
init(title: String, date: Date) {
self.title = title
self.date = date
}
}
Doing it will make each the init
and our conformance to PersistentModel
nonisolated
which suggests 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 signifies that we’re free to create and use Train
cases away from the principle actor.
Not each app will want this or encounter this, particularly while you’re operating code on the principle actor by default. In the event you do encounter this downside for SwiftData fashions, you need to most likely isolate the problematic are to the principle 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 widespread proper now within the Xcode 26 beta; utilizing Codable
objects with default actor isolation.
Fixing Conformance of protocol ‘Encodable’ crosses into principal actor-isolated code and might trigger information races
This error is sort of attention-grabbing and I ponder whether it’s one thing Apple can and will repair throughout the beta cycle. That stated, as of Beta 2 you may run into this error for fashions that conform to Codable
. Let’s have a look at a easy mannequin:
struct Pattern: Codable {
var title: String
}
This mannequin has two compiler errors:
- Round reference
- Conformance of ‘Pattern’ to protocol ‘Encodable’ crosses into principal actor-isolated code and might trigger information races
I’m not precisely positive why we’re seeing the primary error. I feel it is a bug as a result of it is senseless to me in the intervening time.
The second error says that our Encodable
conformance “crossed into principal actor-isolated code”. In the event you dig a bit deeper, you’ll see the next error as an evidence for this: “Most important actor-isolated occasion technique ‘encode(to:)’ can not fulfill nonisolated requirement”.
In different phrases, our protocol conformance provides a principal actor remoted implementation of encode(to:)
whereas the protocol requires this technique to be non-isolated.
The explanation we’re seeing this error will not be fully clear to me however there appears to be a mismatch between our protocol conformance’s isolation and our Pattern
sort.
We will do considered one of two issues right here; we will both make our mannequin nonisolated
or constrain our Codable
conformance to the principle actor.
nonisolated struct Pattern: Codable {
var title: String
}
// or
struct Pattern: @MainActor Codable {
var title: 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 principle actor:
func createSampleOnMain() {
// that is advantageous
let pattern = Pattern(title: "Pattern Occasion")
let information = attempt? JSONEncoder().encode(pattern)
let decoded = attempt? JSONDecoder().decode(Pattern.self, from: information ?? Information())
print(decoded)
}
nonisolated func createSampleFromNonIsolated() {
// this isn't advantageous
let pattern = Pattern(title: "Pattern Occasion")
// Most important actor-isolated conformance of 'Pattern' to 'Encodable' can't be utilized in nonisolated context
let information = attempt? JSONEncoder().encode(pattern)
// Most important actor-isolated conformance of 'Pattern' to 'Decodable' can't be utilized in nonisolated context
let decoded = attempt? JSONDecoder().decode(Pattern.self, from: information ?? Information())
print(decoded)
}
So usually talking, you don’t need your protocol conformance to be remoted to the principle actor to your Codable
fashions when you’re decoding them on a background thread. In case your fashions are comparatively small, it’s doubtless completely acceptable so that you can be decoding and encoding on the principle actor. These operations needs to be quick sufficient typically, and sticking with principal actor code makes your program simpler to purpose about.
One of the best answer will rely in your app, your constraints, and your necessities. At all times measure your assumptions when doable and follow options that be just right for you; don’t introduce concurrency “simply to make sure”. In the event you discover that your app advantages from decoding information on a background thread, the answer for you is to mark your sort as nonisolated
; when you discover no direct advantages from background decoding and encoding in your app you need to constrain your conformance to @MainActor
.
In the event you’ve carried out a customized encoding or decoding technique, you may be operating into a unique error…
Conformance of ‘CodingKeys’ to protocol ‘CodingKey’ crosses into principal actor-isolated code and might trigger information races
Now, this one is a bit trickier. When we now have a customized encoder or decoder, we’d additionally wish to present a CodingKeys
enum:
struct Pattern: @MainActor Decodable {
var title: String
// Conformance of 'Pattern.CodingKeys' to protocol 'CodingKey' crosses into principal actor-isolated code and might trigger information races
enum CodingKeys: CodingKey {
case title
}
init(from decoder: any Decoder) throws {
let container = attempt decoder.container(keyedBy: CodingKeys.self)
self.title = attempt container.decode(String.self, forKey: .title)
}
}
Sadly, this code produces an error. Our conformance to CodingKey
crosses into principal actor remoted code and which may trigger information races. Normally this may imply that we will constraint our conformance to the principle actor and this may resolve our difficulty:
// Most important actor-isolated conformance of 'Pattern.CodingKeys' to 'CustomDebugStringConvertible' can not fulfill conformance requirement for a 'Sendable' sort parameter 'Self'
enum CodingKeys: @MainActor CodingKey {
case title
}
This sadly doesn’t work as a result of CodingKeys
requires us to be CustomDebugStringConvertable
which requires a Sendable
Self
.
Marking our conformance to principal actor ought to imply that each CodingKeys
and CodingKey
are Sendable
however as a result of the CustomDebugStringConvertible
is outlined on CodingKey
I feel our @MainActor
isolation doesn’t carry over.
This may additionally be a tough edge or bug within the beta; I’m undecided.
That stated, we will repair this error by making our CodingKeys
nonisolated
:
struct Pattern: @MainActor Decodable {
var title: String
nonisolated enum CodingKeys: CodingKey {
case title
}
init(from decoder: any Decoder) throws {
let container = attempt decoder.container(keyedBy: CodingKeys.self)
self.title = attempt container.decode(String.self, forKey: .title)
}
}
This code works completely advantageous each when Pattern
is nonisolated
and when Decodable
is remoted to the principle actor.
Each this difficulty and the earlier one really feel like compiler errors, so if these get resolved throughout Xcode 26’s beta cycle I’ll be certain to return again and replace this text.
In the event 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 making an attempt to determine how precisely it matches into the way in which I write code.