RunLoop.main or DispatchQueue.main when using Combine scheduler?

Related but not related.

I was hoping that .receive(on: DispatchQueue.main) would deliver synchronously if the notification was sent from the main thread and asynchronously otherwise. Instead I think I'm seeing* that it always delivers asynchronously to the main thread — even if the original notification was from the main thread.

The consistency might be a good thing, but it means that if performance matters I have to know which threads both the publisher and subscriber are on. What I was hoping was that I could make a declaration of my intent and have Combine magically optimize for it.

===

*Looking at the call stack, async delivery definitely seems to be the case for .receive(on: RunLoop.main). For .receive(on: DispatchQueue.main) it's less clear: the original publisher notification is still on the call stack, but so are calls like dispatch_async. Maybe .receive(on: DispatchQueue.main) is something of a hybrid, ultimately making a sync call from an async request? (When I don't use .receive() at all the call stack is of course much simpler.)

1 Like