I am trying to wrap my head around this piece of code.
Lets say I have a struct S1 defined like this:
nonisolated struct S1 {
@MainActor var title: String = "My title"
nonisolated mutating func updateTitle() {
title = "My new title"
}
}
Firstly, I am trying to understand why does this piece of code compile. My assumption is that updateTitle function should not be able to mutate title variable since updateTitle is nonisolated and title property is marked with @MainActor.
Furthermore if I then define a class C1 like this that holds the S1 value:
nonisolated class C1 {
var s1 = S1()
}
and then use it to mutate the s1 title like this:
var c1 = C1()
await updateTitleConcurrent(c1: c1)
print(c1.s1.title) // this prints "My New Title"
func updateTitleConcurrent(c1: sending C1) async {
await Task { @concurrent in
c1.s1.updateTitle()
}.value
}
The title property will be mutated on some arbitrary thread from the concurrent thread pool and not the main thread. This does not seem correct since the title property is obviously marked with @MainActor
Any suggestion on why this works like that?
for information, I am using Xcode 26 beta 2 with Swift 6 and DefaultActorIsolation set to MainActor.
I am no expert, but instances of struct S1 have value semantics. What does using nonisolated on them mean?
Instead, have you tried to make S1 a class?
nonisolated class S1 {
@MainActor var title: String = "My title"
nonisolated func updateTitle() {
title = "My new title" // Error: Main actor-isolated property 'title' can not be mutated from a nonisolated context
// Mutation of this property is only permitted within the actor
}
}
Yes I also tested the exact same thing you mentioned and for class it seems to work as expected.
My assumption was that structs should work in a similar way and that similar constraints should be applied on them as well in the end.
This still seems like a bug to me that we are allowed to update @MainActor property of a struct within nonisolated function (which can be called on arbitrary thread) unless I am missing something.
Your function is synchronous, so it’s a tricky question: it cannot leave current isolation. And since you have everything default to main actor, compiler might assume that it is safe. Try to introduce asynchronous concurrent function that will call this method.
I think that even though I have everything default to @MainActor the updateTitle function is not on it but rather it should be nonisolated because it is explicitly marked like that.
And because of that my assumption was that I cannot access the @MainActor property from nonisolated synchronous function the same way that is not possible when using a class as @ibex10 showed in his example.