Syntactic sugar for setting properties on an ObservableObject on the main thread from within a Task
MainThreadPropertyAccessor
Syntactic sugar for setting properties on an ObservableObject on the main thread from within a Task.
Task {
self.setOnMain.status = "Now I'll never get purple warnings again!"
}
Installation
You can use the Swift Package Manager by declaring MainThreadPropertyAccessor as a dependency in your Package.swift file:
.package(url: "https://github.com/theisegeberg/MainThreadPropertyAccessor", from: "0.1.0")
For more information, see the Swift Package Manager documentation.
The problem
ObservableObject is often used as a kind of controller for SwiftUI View. After structured concurrency (async/await) was introduced we’ll often need to set the value of a @Published property inside of a ObservableObject. This means wrapping the code in DispatchQueue.main.async { ... } or using a @MainActor annotated method. This can be done, but it’s a lot of code.
The solution
A protocol with no requirements that provides a default extension that exposes only one computed property: .setOnMain. This returns an object that can be subscripted into based on the KeyPath‘s of the ObservableObject that implements the protocol.
Usage
- Add the protocol
MainThreadPropertyAccessorto yourObservableObject - Use
self.setOnMain.somePropertyOfYourObject = newValueto set properties on yourObservableObject
class AnObservableObject: ObservableObject, MainThreadPropertyAccessor {
@Published var status:String = ""
func updateStatus() {
Task {
// Do some async work
self.status = "Will update the UI from a background thread" // Warning!
self.setOnMain.status = "Will update the UI from the main dispatch queue" // ?
}
}
}