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.
2
Answers
Just mark
setUp()
as @MainActorApproach:
override func setUp() async throws
insteadModel:
Testcase: