In SwiftUI, updating the UI from background threads is not allowed. Any changes to the published properties should be done on the main thread. To update model values from background threads, you can use the receive(on:)
operator to switch to the main thread before publishing the changes.
Here's an example of how to use the receive(on:)
operator to correctly publish values from background threads:
import SwiftUI
import Combine
class MyViewModel: ObservableObject {
@Published var myProperty: Int = 0
private var cancellables = Set<AnyCancellable>()
func updatePropertyInBackground() {
DispatchQueue.global().async {
// Perform background work
let newValue = 123
DispatchQueue.main.async {
// Switch to main thread before updating the property
self.myProperty = newValue
}
}
}
func updatePropertyWithPublisher() {
Just(456)
.receive(on: DispatchQueue.main) // Switch to main thread
.sink { newValue in
self.myProperty = newValue
}
.store(in: &cancellables)
}
}
In the updatePropertyInBackground()
method, we perform the work on a background thread and then switch to the main thread using DispatchQueue.main.async
before updating the myProperty
property.
In the updatePropertyWithPublisher()
method, we use the receive(on:)
operator on a Combine publisher to switch to the main thread before updating the property in the sink closure.
By ensuring updates to published properties are always done on the main thread, you can avoid the "Publishing changes from background threads is not allowed" error in SwiftUI.