ios – Why do I need to use `@MainActor` when I’m already using `.receive(on: .main)`?


I keep getting a runtime error:

Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.

This occurs when I’m setting my @Published array = to a new value. That setting of the array occurs within a .receive(on: DispatchQueue.main).sink block.

Example code:

class MyClass: ObservableObject {
    @Published var movies: [Movie] = []

    var retrievePublisher: AnyCancellable?

    func retrieve() async throws {
        retrievePublisher = (await retrieveMovies()).receive(on: DispatchQueue.main).sink(receiveCompletion: { _ in
        }, receiveValue: { [weak self] newArray in
            guard let self else { return }

            movies = newArray.result
        })
    }
}

func retrieveMovies() async -> AnyPublisher<RetrieveResult<Movie>, CustomError> {
    // ...
}

However, if I tag the class with @MainActor, the runtime error does not occur anymore.

Additionally, if I set a breakpoint on that movies variable or where I’m setting it, I can observe that everything is indeed occurring on the main thread.

Why is @MainActor necessary in this case? What about .receive(on: DispatchQueue.main) is causing the error: Publishing changes from background threads is not allowed?

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img