Changing state asynchronously in SwiftUI

I'm fairly new to Swift and struggling to go beyond the basics with SwiftUI's state management. My app uses Firebase to authenticate itself with a server, so it goes through a series of state changes when logging in that the UI needs to respond to.

Because logging in goes through these multiple stages, I want to use async/await to make my code more readable than using a series of completion callbacks. The trouble is I can't update my state variables from an async function if SwiftUI is observing them via @ObservedObject or similar.

One way to fix that is to never update state directly from an async function, but use DispatchQueue.main.async instead. The trouble is, this adds noise, and Apple discourage it. Instead of changing how you set the state, you're supposed to change how you listen to it, by using .receive(on:).

The trouble is, I think the point where I would need to do that is buried somewhere in what @ObservedObject does behind the scenes. Why doesn't it already use .receive(on:)? Can I get or write a version that does without having to spend ages learning intricate details of SwiftUI or Combine?

Answering my own question, I later found out about @MainActor, which seems to be just what I need.

Changing state asynchronously in SwiftUI
 
 
Q