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
MainThreadPropertyAccessor
to yourObservableObject
- Use
self.setOnMain.somePropertyOfYourObject = newValue
to 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" // ?
}
}
}