We'd like to make use of the @MainActor Annotation for our ViewModels in an existing SwiftUI project, so we can get rid of DispatchQueue.main.async and .receive(on: RunLoop.main).
@MainActor
class MyViewModel: ObservableObject {
private var counter: Int
init(counter: Int) {
self.counter = counter
}
}
This works fine when initializing the annotated class from a SwiftUI View. However, when using a SwiftUI Previews or XCTest we also need to initialize the class from outside of the @MainActor context:
class MyViewModelTests: XCTestCase {
private var myViewModel: MyViewModel!
override func setUp() {
myViewModel = MyViewModel(counter: 0)
}
Which obviously doesn't compile:
Main actor-isolated property 'init(counter:Int)' can not be mutated from a non-isolated context
Now, obviously we could also annotate MyViewModelTests with @MainActor as suggested here.
But we don't want all our UnitTests to run on the main thread. So what is the recommended practice in this situation?
Annotating the init function with nonisolated as also suggested in the conversation above only works, if we don't want to set the value of variables inside the initializer.
Just mark
setUp()as @MainActor