Assume having a code like this:
@globalActor
public struct FooActor: GlobalActor {
public actor ActorType { }
public static let shared: ActorType = ActorType()
}
@MainActor
protocol SomeMainActor {
var value: Int { get }
@FooActor var protectedStorage: [String] { get set }
}
final class Test: SomeMainActor {
let value: Int = 0
@FooActor var protectedStorage: [String] = []
}
actor TestActor {
@MainActor private var someVar: SomeMainActor?
init(withVar: SomeMainActor?) {
self.someVar = withVar // Main actor-isolated property 'someVar' can not be mutated from a non-isolated context
}
@MainActor
var value: Int? {
self.someVar?.value
}
func add() {
Task { @FooActor in
await self.someVar?.protectedStorage.append("test") // Non-sendable type '(any SomeMainActor)?' in implicitly asynchronous access to main actor-isolated property 'someVar' cannot cross actor boundary
}
}
}
let test = TestActor(withVar: Test())
await test.add()
Tried different workarounds for init, like the code below. having errors like these:
init(withVar: SomeMainActor?) {
Task { @MainActor in // 'self' captured by a closure before all members were initialized
self.someVar = withVar // Sending 'someVar ' risks causing data races
}
}
(Couldn't reproduce this in playground, but got on a real project I try to migrate)
If I remove @MainActor from someVar
or value
getter, I get this errors:
actor TestActor {
private var someVar: SomeMainActor?
...
@MainActor
var value: Int? {
self.someVar?.value // Actor-isolated property 'someVar' can not be referenced from the main actor
}
var value: Int? {
self.someVar?.value // Main actor-isolated property 'value' can not be referenced on a non-isolated actor instance
}
var value: Int? {
get async {
await self.someVar?.value // Non-sendable type 'any SomeMainActor' passed in implicitly asynchronous call to main actor-isolated property 'value' cannot cross actor boundary
}
}
Also, got this weirdness with add method if I remove @FooActor
task:
func add() async {
await self.someVar?.protectedStorage.append("test") // Global actor 'FooActor'-isolated property 'protectedStorage' can not be mutated on a non-isolated actor instance
// No 'async' operations occur within 'await' expression
}
I want to do everything right to ensure my code is swift 6 ready.
How can I work with one actor isolated values from another actor context with no compiler errors, no boilerplate, thread safe and compact enough?
Why so many errors on all approaches I try (no matter what I try).
What is the right way to store another actor-isolated variables within another actor?