Actor initializer warning

actor Person {
   init() {
     self.name = "Test" // ok. no warning
   } 
}

But

actor Person {
    
    var name: String = ""
    let disposeBag = DisposeBag()
    init() {
        Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.asyncInstance)
            .subscribe(onNext: { _ in
                self.name = "Test" // Actor-isolated property 'name' can not be mutated from a non-isolated context; this is an error in Swift 6
            }).disposed(by: disposeBag)
    }

Why is the warning occurring there?

Like the warning/error says, you're performing concurrent (unsafe) access to the actors mutable name property.

The onNext's purpose is to be invoked concurrently, so... "outside of the actor", so that self.name = ... is not synchronized properly and thus the warning.

A safe version of that would do something like await self.setName(name) basically, where the setName has to perform a suspension and hop to the actor to perform the name setting. You may not be able to do that easily from inside the onNext closure unless it supports async closures.

"outside of the actor" i'm still confused :joy:

Instance methods are isolated so this problem doesn't happen.
But init isn't isolated and that causes this problem?

It depends on the exact declaration of those methods you're showing here; if you want an in depth analysis please provide the method declarations of subscribe etc.


A synchronous initializer is not isolated to the actor; that's right, an async actor initializer becomes isolated to the actor though, so IF (and only if) your closure taking method there does the inherit executor trickery it might work... but I don't expect external libraries to be doing this trick -- it's an underscored attribute.

2 Likes