Main actor-isolated property 'foo' can not be mutated from a non-isolated context; this is an error in Swift 6
in code constructs like this:
@MainActor
final class SomeViewModel: ObservableObject {
@Published private(set) var state = ...
private let foo: String
private let bar: (String) -> Void
nonisolated init(
foo: String,
bar: @escaping (String) -> Void
) {
self.foo = foo // <-- No warning here
self.bar = bar // <-- Warning here
}
...
}
Questions:
Why shouldn't I be able to set private constants in the initialiser of a class like this from a non-isolated context? (The instance is not created, so how can it be "mutating" the private let property?
Why do I only get the warning for bar and not also for foo?
Is adding nonisolated to the private let property with the warning an acceptable fix for this?
String conforms to Sendable, so it is safe for foo to cross isolation boundary. Closure you pass to init is not. Adding @Sendable attribute will fix the warning.
Because bar property by not being sendable cannot safely cross isolation boundary (from main-actor isolation to nonisolated context) at the time of assign. Probably, compiler message here not that descriptive; the case not in "mutability", but non-Sendable closure is crossing isolation boundary.
Depends on use case, e.g. you would need to access this nonisolated property from nonisolated context. Making it @Sendable will make it usable within the class easily, and probably this is better strategy to resolve the warning.
tldr; the compiler should not let you write nonisolated on stored properties of Sendable/actor-isolated types when the stored property type is not Sendable. This is fixed in the Swift 6 language mode.
Using Xcode 16 beta and enable Swift 6, I can remove the warning with below code
@MainActor
final class SomeViewModel: ObservableObject {
@Published private(set) var state = ...
private let foo: String
nonisolated private let bar: @Sendable (String) -> Void
nonisolated init(foo: String,
bar: @Sendable @escaping (String) -> Void) {
self.foo = foo
self.bar = bar
}
}