Joachim<p><a href="https://hachyderm.io/tags/SwiftUI" class="mention hashtag" rel="nofollow noopener" target="_blank">#<span>SwiftUI</span></a> and <a href="https://hachyderm.io/tags/concurrency" class="mention hashtag" rel="nofollow noopener" target="_blank">#<span>concurrency</span></a> question:</p><p>I see a lot of online recommendations online that say to always use `@MainActor` with `@Observable` and ObservableObject including <span class="h-card" translate="no"><a href="https://mastodon.social/@twostraws" class="u-url mention" rel="nofollow noopener" target="_blank">@<span>twostraws</span></a></span>, here: <a href="https://www.hackingwithswift.com/quick-start/concurrency/important-do-not-use-an-actor-for-your-swiftui-data-models" rel="nofollow noopener" translate="no" target="_blank"><span class="invisible">https://www.</span><span class="ellipsis">hackingwithswift.com/quick-sta</span><span class="invisible">rt/concurrency/important-do-not-use-an-actor-for-your-swiftui-data-models</span></a> </p><p>But it sounds wrong to me. Am I missing something?</p><p>Let’s talk about the Observable macro first: <br>It seems like the recommendation to use a MainActor annotation here comes from people a) having been bit by the runtime issue seen for ObservableObject (see below) and b) people having learned the lesson from UIKit of „don’t touch the UI from a background thread“.</p><p>But when we modify a property on an Observable-macro-object from a background thread, which in turn triggers a UI update, the `body` property still executes on the main thread. (Verified via breakpoints)<br>There is no runtime issue or anything that suggests this would be wrong. People just seem to believe it is?</p><p>For ObservableObject, if you modify a `@Published` property from a background thread, you see a runtime issue in Xcode that says „Publishing changes from a background thread is not allowed.“, so people annotate their ObservableObjects with a main actor annotation or use DispatchQueue.main.async to make changes to the property. </p><p>But afaict this is a Combine warning not a SwiftUI warning and the Observable macro doesn’t use Combine.</p><p>But even in the ObservableObject case why is that an issue? The docs for the Combine property wrapper don’t state that it must only be modified on the main thread. Afaik, in Combine the observer chooses where to receive an update, you can simply receive(on:) to another queue. And it seems that SwiftUI does. Even in that case the body property of an observing view is not executed on a background thread, even if the property change is.</p><p>So even there I don’t see why dispatching model updates to the main queue is necessary, SwiftUI should handle that and at first glance it seems like it does, Combine just complains anyway. </p><p>So I can’t find a compelling reason why that’s necessary (except for „we‘ve always done it this way“). Yet, there is a runtime issue for the Published case and everyone seems to be convinced it’s necessary. What am I missing?</p>