100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Swift

ObservableObject and @ObservedObject

Learn how the pre-iOS 17 ObservableObject protocol and @Published/@ObservedObject let reference-type models publish changes that drive SwiftUI view updates.

State & Data FlowIntermediate9 min readJul 8, 2026
Analogies

ObservableObject and @ObservedObject

While @State is ideal for simple, view-local value types, real apps often need shared, reference-type models—view models, data controllers, session managers—that outlive a single view and are used across a screen or the whole app. Before the @Observable macro (introduced in iOS 17), SwiftUI's answer was the ObservableObject protocol from Combine: a class conforms to ObservableObject, marks the properties it wants to publish with @Published, and views that need to react to those changes hold the object with @StateObject (if they create/own it) or @ObservedObject (if it's passed in from elsewhere). This pattern is still present throughout production codebases and third-party libraries, so understanding it remains essential even as newer code adopts @Observable.

🏏

Cricket analogy: A single batsman tracking his own strike rate (@State) is simple, but a shared team scorebook (ObservableObject) that every player and commentator reads from needs a dedicated scorer marking updates (@Published); old scorebooks are still used at club-level matches even as digital ones take over.

@Published and Combine's objectWillChange

Every property wrapped with @Published automatically sends a signal through the class's synthesized objectWillChange publisher immediately before the property changes. SwiftUI subscribes to that publisher for any view observing the object, and when it fires, SwiftUI schedules that view's body to be re-evaluated. Only properties actually marked @Published participate—plain stored properties on an ObservableObject do NOT trigger view updates, which is a frequent source of confusing 'my UI didn't refresh' bugs.

🏏

Cricket analogy: Only the official scoreboard operator's announced updates (@Published) get relayed to the stadium screen; a fielder's private notebook tally of runs saved doesn't trigger any board update no matter how accurate it is.

swift
final class CartViewModel: ObservableObject {
    @Published var items: [String] = []
    @Published var isCheckingOut = false

    var itemCount: Int { items.count }  // not @Published, but derived from a @Published property

    func add(_ item: String) {
        items.append(item)
    }
}

@StateObject vs @ObservedObject

The critical distinction is ownership and lifecycle. @StateObject tells SwiftUI 'create this object once and keep it alive for the lifetime of this view,' surviving body re-evaluations just like @State—use it exactly where the object is instantiated. @ObservedObject makes no ownership claim; it simply subscribes to an object handed to it from outside. If you use @ObservedObject at the point of creation, the object gets recreated (and its state lost) every time the parent view re-renders, which is a classic bug.

🏏

Cricket analogy: If a franchise re-drafts, or recreates, its star scorer every single match instead of retaining the same one for the season (@StateObject), all accumulated season stats reset each game, a classic and costly mistake.

swift
struct CartScreen: View {
    @StateObject private var viewModel = CartViewModel()  // owns it

    var body: some View {
        CartSummary(viewModel: viewModel)
    }
}

struct CartSummary: View {
    @ObservedObject var viewModel: CartViewModel  // borrows it

    var body: some View {
        Text("Items: \(viewModel.itemCount)")
    }
}

A handy rule of thumb: if the = CartViewModel() initializer expression appears directly in your property declaration, that view is the owner and should use @StateObject. If the object arrives via an initializer parameter from a parent, use @ObservedObject.

Declaring @ObservedObject private var viewModel = CartViewModel() at the creation site is a very common bug: every time the parent view re-renders, a brand-new CartViewModel is constructed, silently discarding all prior state (like cart items). Always use @StateObject at the creation site instead.

  • ObservableObject is a Combine-based protocol; conforming classes gain a synthesized objectWillChange publisher.
  • Only properties marked @Published trigger SwiftUI view updates when they change.
  • @StateObject owns and persists the object across a view's re-renders—use it where the object is created.
  • @ObservedObject subscribes to an object owned elsewhere—use it when the object is passed in as a parameter.
  • Creating the object with @ObservedObject at its instantiation site causes state loss on every re-render.
  • This pattern predates the @Observable macro but remains common in existing codebases and libraries.

Practice what you learned

Was this page helpful?

Topics covered

#Swift#IOSWithSwiftUIStudyNotes#MobileDevelopment#ObservableObjectAndObservedObject#ObservableObject#ObservedObject#Published#Combine#StudyNotes#SkillVeris