TBF… there are also "spi
only" functions (like willSet
and didSet
) that are only intended to be available in SwiftUI. So Observable
is "outside" SwiftUI… but also "sort of kind of" meant to be private in some places to SwiftUI.
Sure, and I had thought about using it to reactively update an audio DSP graph.
What's "spi only"?
I think I've seemed overly negative toward @Observable
in this thread. It has been a good improvement over ObservableObject
and I really don't mean to come off as not being appreciative of the work of those involved
The trend in SwiftUI from ObservableObject
-> @Observable
has moved toward fewer footguns, so I was just musing about whether it could be pushed further in that direction by having strong guarantees of UI updates.
The thing is that, the way @Observable
currently functions, is a very niche mechanism that would likely not really justify it being a default language-wide construct.
Observation in UI frameworks has one pretty straightforward job: to set a dirty flag on some view hierarchy and schedule a render loop. A lot of problems, even those that on the surface would benefit from subscribing to some state, could want to do this with different granularity. Keypaths are another limitation: what if your state change isn't as easily modeled through them (say, you're writing to a texture on the GPU)?
The suggestion sounds just too SwiftUI-centric to me, and as noted above, incorrect defaults could skew people toward antipatterns and false assumptions more often than they would be helpful otherwise.
Other language constructs were added for SwiftUI, such as view builders, property wrappers, opaque result types, probably others I'm forgetting.
Re GPU textures, I think its fine if modifying a texture does not cause your UI to update. If you're advanced enough to deal with MTLTexture
directly, you can handle that limitation. That said, it's not too hard to imagine a world in which CPU-side mutation of texture memory could trigger invalidation of some derived state.
There's also no such thing as an "incorrect" default. There's no fact of the matter here, only intuition about what is better or worse. There is, however, a correctness issue as I have defined above with respect to view updates (which has not been addressed in the replies).
I appreciate the goal... to make it right without any effort from the developer.
Thinking out loud. If you could make the state that drives your view a short string of bytes (let's say 1K) then it could be relatively quickly compared with say memcmp against the old string of bytes, even 120 times a second with no much CPU spent, and if the change is detected then the view needs to be re-rendered. Now the question is how to distill your state (however complicated that is and however is it spread across your data structures) into that concise byte string, and do that quickly.