So as a general rule, we need to conform View Models to MainActor for the sake of UI updates happening on the MainActor, but that causes contention on the MainActor when testing.

I wonder if there’s a way to default isolate, maybe via a parameter, to the MainActor, but for the sake of testing to allow it to be effectively nonisolated? #swiftlang #iosdev

@rhysmorgan I don’t think that general rule holds up as well as it once did. I believe you should be defaulting to nonisolated and using MainActor only when it is truly essential. And it’s not that often!
@mattiem Oh, even for View Models? Is that with the approachable concurrency settings specifically, or in general?
@rhysmorgan @mattiem just switch default isolation to nonisolated.
@matadan @mattiem Oh, I always do. I hate the MainActor-default isolation mode.
What I want to achieve is the ability to use non-isolated View Models that can be observed from views, and ideally aren't split-isolation types.

@rhysmorgan @matadan I think NonisolatedNonsendingByDefault makes it much more ergonomic definitely (Approachable Concurrency turns that on).

Nonisolated is the best option here for this kind of work for sure.

I’m pretty sure you can do what you want here in general. The biggest problem is usually callbacks.

@mattiem @matadan Yes, nonisolated(nonsending) is one of the features that @pointfreeco have briefly covered at the start of their newest series.
Their new tooling for TCA 2.0 is going to allow features to be MainActor-isolated when necessary, and totally non-MainActor-isolated to avoid contention, and allow full parallelisation when testing.
I'm keen to figure out if there's a way to achieve the same thing with View Models, where the core of the feature isn't wrapped in that harness.
@rhysmorgan @matadan @pointfreeco I don’t think the concept of “ViewModel” is particularly special here. All that really matters is if you have dependencies on MainActor functions inside the type. You should try I bet it works!
@mattiem @rhysmorgan @pointfreeco I was going to say the same thing. ;)
@mattiem @matadan @pointfreeco OK, lol, this it totally breaking my brain now.
This all just compiles and works, in Swift 6 mode with Approachable Concurrency, even without the View Model being MainActor-isolated? Even tho the MainActor-isolated View is observing non-MainActor-isolated state? And this allows me to write non-MainActor-isolated Swift Testing tests, and avoid MainActor-contention? 🤯

@rhysmorgan @matadan @pointfreeco you got it. Here I wrote a bit about this technique in case it helps.

https://www.massicotte.org/blog/non-sendable-first-design/

Non-Sendable First Design

The easiest way to design concurrent systems in Swift was hiding in plain sight.

massicotte.org

@mattiem @matadan @pointfreeco I am... quite confused right now (about to read your post), but also very happy that this is possible.

https://github.com/rhysm94/NonIsolatedViewModels

Pushed this to GitHub as a demo, explicitly adding `nonisolated` to the View Model just to be 110% sure. And it just works. nonisolated View Model, properties updated from an async method being read from a MainActor-isolated View... and it just works. 🤯 So what I wanted is possible - no MainActor contention for tests!

@mattiem @matadan @pointfreeco

"Side-stepping the problem entirely, with a simpler type no less, almost feels like cheating."

Yep. Yep, it absolutely does feel like cheating! This is genuinely revolutionary – especially given I'm working in a codebase that's undergoing architectural + testing refactoring, and I can make these kinds of improvements at this early stage!!

@rhysmorgan @mattiem @pointfreeco nonisolated things can run on MainActor because they are not isolated to another isolation context. I think that’s right. It is difficult to get straight TBH.
@matadan @mattiem @pointfreeco I’m just shocked that even with an Observation happening from that nonisolated state, with the update being triggered from a nonisolated, @.concurrent async closure, Swift and SwiftUI are all happy, all OK!