I don't understand why actors init (also for global actors) need to be isolated. When I try to mark the initializer as nonisolated, I get the following error:
Global actor 'MainActor'-isolated property 'container' cannot be mutated from a non-isolated context; this is an error in Swift 6.
Why do initializers have to be isolated at all?
Can I really initialize the same object from different threads and got an concurrency-error?
It seems impossible to do so.
Could someone explain how this works and why initializers must be isolated?
@MainActor struct Foo {
var x = SomeUIKitClass.crashesWhenCalledOffMainThread()
nonisolated init() {
// There is no possible way for this to run
}
}
Keeping in mind that default values are implicitly assigned in every init, there is no possible way for a nonisolated init to work here. If the initializer runs off the main thread, the default value cannot be (synchronously) retrieved. So, there are really two choices:
@MainActor types can have fields whose default values are themselves @MainActor;
@MainActor types can have nonisolated inits.
Not having the former would be more unintuitive (at least in my opinion), so Swift forbids the latter instead.
Yes, you right. Sorry, but I'm referring to the simpler case.
actor SomeActor {
let dependency1: String
nonisolated init(dependency1: String) { // 'nonisolated' on an actor's synchronous initializer is invalid; this is an error in Swift 6
self.dependency1 = dependency1
}
}
@MainActor
final class SomeMainActor {
let dependency1: DependencyProtocol
nonisolated init(dependency1: DependencyProtocol) { // Main actor-isolated property 'dependency1' can not be mutated from a non-isolated context; this is an error in Swift 6
self.dependency1 = dependency1
}
}
In this case, I just want to initialize the actor's property. I don't intend to access any properties after initialization.
I simply want to set the actor's properties during initialization, so I don't see any concurrency issues in this scenario.