-
Notifications
You must be signed in to change notification settings - Fork 1
Open
Description
Good questions. Short answer: yes — writing view models as class MyViewModel: ObservableObject { @Published … } is increasingly considered “old style.” With recent Swift / SwiftUI versions the trend is shifting toward using the newer @Observable macro (from the standard Observation framework) — but it’s not a strict “you must always switch.” How you mark your view models depends on your app’s deployment targets, complexity, and requirements.
Apple Developer
+2
Use Your Loaf
+2
Here’s a detailed breakdown using your example:
✅ Why @Observable is now preferred (or often recommended)
The @Observable macro — available since Swift 5.9 / iOS 17+ / macOS 14+ — automatically synthesizes observation support for a class. You don’t need to declare conformance to ObservableObject, nor mark each property with @Published.
Use Your Loaf
+2
SwiftLee
+2
The resulting observation is property-level, not “object-level.” This means only when a property actually used by a view changes will SwiftUI re-evaluate that part of the UI. That tends to reduce unnecessary view redraws and improves performance.
flyingharley.dev
+2
Medium
+2
It reduces boilerplate — fewer wrappers, less Combine scaffolding (objectWillChange, @Published, etc.).
flyingharley.dev
+2
Medium
+2
According to migration guides from Apple and community posts, @Observable is essentially the future of SwiftUI model-state design.
Apple Developer
+2
Use Your Loaf
+2
Because of these benefits, many developers are shifting “view models / models” from ObservableObject + @Published → @Observable.
⚠️ But @Observable isn’t a perfect drop-in — caveats you should be aware of
It requires iOS 17 / macOS 14 / Swift 5.9+. If your app supports earlier OS versions (e.g. iOS 16 or older), @Observable isn’t an option unless you conditionally fall back or drop support.
Medium
+1
Because @Observable doesn’t rely on Combine, some patterns — e.g. manual publishers, Combine pipelines, custom AnyCancellables — don’t directly translate. If your view model currently uses Combine for side-effects, debounce, cancellation, etc., migrating may require rethinking those parts.
Stack Overflow
+1
For nested or hierarchical data models (models containing other models), you need to mark all relevant reference types with @Observable (or otherwise make them observable) if you want changes to propagate.
Medium
+1
Concurrency / threading: though @Observable itself is thread-safe, when used with SwiftUI you still need to ensure that state updates occur on the main thread (e.g. via @MainActor). Otherwise, SwiftUI may “skip” updates or behave unpredictably.
[Swift Forums](https://forums.swift.org/t/do-update-to-observable-properties-have-to-be-done-on-the-main-thread/74954?utm_source=chatgpt.com)
🔄 What you should do in your case (given the example you showed)
Given your ChatViewModel, here’s how I'd approach refactoring — and when I’d choose not to:
If your app deployment target is iOS 17+ only (or you’re OK dropping older support) → migrate to @Observable.
Change the class declaration to something like:
import Observation // or import whatever module
@Observable
@MainActor // you can still keep this if your view model is main-thread bound
final class ChatViewModel {
// remove @Published
var creationMessage: String?
// other stored properties
}
Remove : ObservableObject, remove @Published.
In your SwiftUI view, instead of @StateObject / @ObservedObject, use @State (or plain let/var, if you know the lifetime) to hold the view model — because lifecycle-management for an @Observable object is up to you.
Medium
+2
Donny Wals
+2
Keep @MainActor (if your view model performs UI-related updates) — that’s still sensible. The new Observation framework doesn’t replace the need to ensure UI-state mutations happen on the main thread.
Swift Forums
+1
Metadata
Metadata
Assignees
Labels
No labels
Projects
Status
No status