0
0
iOS Swiftmobile~15 mins

ObservableObject protocol in iOS Swift - Deep Dive

Choose your learning style9 modes available
Overview - ObservableObject protocol
What is it?
The ObservableObject protocol is a way to create data models in SwiftUI that can notify the user interface when their data changes. When a class adopts ObservableObject, it can publish updates to its properties. Views that watch these objects automatically refresh when the data changes, keeping the UI in sync with the data.
Why it matters
Without ObservableObject, the UI would not know when data changes, so it would show outdated information. This would make apps feel broken or unresponsive. ObservableObject solves this by creating a clear link between data and UI updates, making apps dynamic and interactive without complex manual updates.
Where it fits
Before learning ObservableObject, you should understand basic Swift classes and SwiftUI views. After mastering ObservableObject, you can learn about advanced state management techniques like Combine framework, @StateObject, and environment objects to build scalable apps.
Mental Model
Core Idea
ObservableObject is a data model that tells the UI when its data changes so the UI can update automatically.
Think of it like...
Imagine a weather station that measures temperature and sends alerts to your phone whenever the temperature changes. The weather station is the ObservableObject, and your phone screen is the UI that updates when it gets the alert.
┌───────────────┐       change detected       ┌───────────────┐
│ ObservableObj │ ──────────────────────────▶ │ SwiftUI View  │
│  (data model) │                            │ (user interface)│
└───────────────┘                            └───────────────┘
Build-Up - 6 Steps
1
FoundationWhat is ObservableObject Protocol
🤔
Concept: Introduce ObservableObject as a protocol for data models that can notify changes.
In SwiftUI, ObservableObject is a protocol you add to a class to make it able to announce when its data changes. This helps the UI know when to refresh. You mark properties with @Published to say which data changes should trigger updates.
Result
You get a class that can tell SwiftUI views to update when its data changes.
Understanding ObservableObject is key to connecting your data and UI in a reactive way.
2
FoundationUsing @Published Properties
🤔
Concept: Learn how to mark properties with @Published to trigger UI updates.
Inside an ObservableObject class, you use @Published before a property to make it send change notifications automatically. For example: class Counter: ObservableObject { @Published var count = 0 } When count changes, views watching this object refresh.
Result
Changing a @Published property causes views observing the object to update.
Knowing which properties to mark @Published controls what changes the UI reacts to.
3
IntermediateConnecting ObservableObject to Views
🤔Before reading on: Do you think views automatically watch all ObservableObjects or do you need to tell them explicitly? Commit to your answer.
Concept: Learn how to link an ObservableObject to a SwiftUI view using @ObservedObject or @StateObject.
To make a view watch an ObservableObject, you declare a property with @ObservedObject or @StateObject: struct ContentView: View { @ObservedObject var counter = Counter() var body: some View { Text("Count: \(counter.count)") } } @ObservedObject is for observing an external object; @StateObject is for owning the object inside the view.
Result
The view updates its UI automatically when the ObservableObject changes.
Explicitly connecting the data model to the view ensures the UI stays in sync with data changes.
4
IntermediateDifference Between @ObservedObject and @StateObject
🤔Before reading on: Which do you think creates and owns the ObservableObject, @ObservedObject or @StateObject? Commit to your answer.
Concept: Understand ownership and lifecycle differences between @ObservedObject and @StateObject.
@StateObject creates and owns the ObservableObject, keeping it alive as the view updates. Use it when the view is responsible for the data. @ObservedObject watches an ObservableObject created elsewhere. Use it when the data is passed in. Choosing correctly prevents bugs like data resetting or views not updating.
Result
Proper use of these wrappers manages data lifecycle and UI updates correctly.
Knowing ownership clarifies how to manage data and avoid common SwiftUI bugs.
5
AdvancedObservableObject and Combine Integration
🤔Before reading on: Do you think ObservableObject uses Combine framework internally or is it unrelated? Commit to your answer.
Concept: Learn that ObservableObject uses Combine's Publisher to send change notifications.
ObservableObject uses Combine's ObservableObjectPublisher internally. When a @Published property changes, it sends events through Combine's publisher system. This lets SwiftUI subscribe and update views reactively. You can also manually send updates by calling objectWillChange.send() if needed.
Result
ObservableObject leverages Combine to efficiently notify changes and update UI.
Understanding Combine under the hood helps debug and extend reactive data flows.
6
ExpertManual Control of Change Notifications
🤔Before reading on: Can you manually trigger UI updates in ObservableObject without @Published? Commit to your answer.
Concept: Explore how to manually send change notifications for complex scenarios.
Sometimes you want to notify changes without @Published. You can call objectWillChange.send() inside your ObservableObject class to tell views to refresh. Example: class ManualNotifier: ObservableObject { let objectWillChange = ObservableObjectPublisher() var value = 0 { willSet { objectWillChange.send() } } } This gives fine control over when UI updates happen.
Result
You can optimize or customize UI updates beyond automatic @Published triggers.
Knowing manual notification unlocks advanced reactive patterns and performance tuning.
Under the Hood
ObservableObject uses the Combine framework's ObservableObjectPublisher to broadcast changes. When a @Published property changes, it automatically calls objectWillChange.send(), which emits an event. SwiftUI views subscribe to these events and refresh their body when notified. This creates a reactive data flow from model to UI without manual refresh calls.
Why designed this way?
SwiftUI needed a simple, declarative way to keep UI and data in sync. Using Combine's publisher system allowed Apple to build on an existing reactive framework, avoiding reinventing the wheel. This design separates data logic from UI, making code cleaner and easier to maintain.
┌───────────────┐
│ ObservableObj │
│  (class)     │
│ @Published   │
│ properties   │
└──────┬────────┘
       │ changes
       ▼
┌───────────────┐
│ objectWillChange│
│  (Publisher)   │
└──────┬────────┘
       │ emits event
       ▼
┌───────────────┐
│ SwiftUI Views │
│ subscribe to │
│ objectWillChange│
└──────┬────────┘
       │ refresh UI
       ▼
┌───────────────┐
│ Updated UI    │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does marking a property @Published guarantee the UI updates instantly? Commit yes or no.
Common Belief:Marking a property @Published means the UI updates immediately and always.
Tap to reveal reality
Reality:UI updates happen on the main thread asynchronously after the property changes, not instantly. Also, if the view is not observing the object properly, updates won't happen.
Why it matters:Assuming immediate updates can cause bugs when UI lags or does not refresh, leading to confusing user experiences.
Quick: Can you use ObservableObject with structs? Commit yes or no.
Common Belief:ObservableObject can be used with structs just like classes.
Tap to reveal reality
Reality:ObservableObject requires a class because it needs reference semantics to manage change notifications. Structs are value types and cannot conform to ObservableObject.
Why it matters:Trying to use ObservableObject with structs leads to compiler errors and confusion about data flow.
Quick: Does @ObservedObject create and own the ObservableObject instance? Commit yes or no.
Common Belief:@ObservedObject creates and owns the ObservableObject instance inside the view.
Tap to reveal reality
Reality:@ObservedObject only observes an existing ObservableObject passed in; it does not create or own it. @StateObject is used to create and own the instance.
Why it matters:Misusing @ObservedObject can cause data to reset or views to not update properly, causing bugs.
Quick: Is it safe to call objectWillChange.send() from any thread? Commit yes or no.
Common Belief:You can call objectWillChange.send() from any thread safely.
Tap to reveal reality
Reality:objectWillChange.send() must be called on the main thread because UI updates happen there. Calling it from background threads can cause crashes or undefined behavior.
Why it matters:Ignoring thread safety leads to app crashes and unstable UI.
Expert Zone
1
ObservableObjectPublisher is a class, so multiple calls to objectWillChange.send() in quick succession coalesce updates to avoid redundant UI refreshes.
2
Using manual objectWillChange.send() allows batching multiple property changes into a single UI update, improving performance.
3
@Published uses property wrappers that synthesize willSet observers internally, but you can override this behavior for custom logic.
When NOT to use
ObservableObject is not suitable for simple, local state inside a single view; use @State instead. For global app state shared across many views, consider using environment objects or external state management libraries like Redux or Combine pipelines.
Production Patterns
In production, ObservableObject is often combined with dependency injection to provide data models to views. Developers use @StateObject at the root view to own data and @ObservedObject in child views to observe it. Manual objectWillChange.send() is used for complex models where multiple properties change together.
Connections
Publisher-Subscriber Pattern
ObservableObject implements this pattern using Combine publishers to notify subscribers (views).
Understanding this pattern clarifies how data changes propagate reactively in SwiftUI.
Model-View-ViewModel (MVVM)
ObservableObject is often used to build the ViewModel layer that holds app data and business logic.
Knowing MVVM helps organize code so ObservableObject cleanly separates UI from data.
Event-Driven Systems (Computer Science)
ObservableObject follows event-driven principles where data changes trigger events that update the UI.
Recognizing this connection helps understand reactive programming beyond mobile apps.
Common Pitfalls
#1UI does not update when data changes.
Wrong approach:class Counter: ObservableObject { var count = 0 } struct ContentView: View { @ObservedObject var counter = Counter() var body: some View { Text("Count: \(counter.count)") } }
Correct approach:class Counter: ObservableObject { @Published var count = 0 } struct ContentView: View { @ObservedObject var counter = Counter() var body: some View { Text("Count: \(counter.count)") } }
Root cause:Forgetting to mark properties with @Published means changes do not notify the UI.
#2Data resets unexpectedly when view reloads.
Wrong approach:struct ContentView: View { @ObservedObject var counter = Counter() var body: some View { Text("Count: \(counter.count)") } }
Correct approach:struct ContentView: View { @StateObject var counter = Counter() var body: some View { Text("Count: \(counter.count)") } }
Root cause:Using @ObservedObject to create the object causes it to be recreated on view reloads; @StateObject owns it properly.
#3Calling objectWillChange.send() from background thread causes crash.
Wrong approach:DispatchQueue.global().async { self.objectWillChange.send() self.value = 10 }
Correct approach:DispatchQueue.main.async { self.objectWillChange.send() self.value = 10 }
Root cause:UI updates must happen on the main thread; calling from background threads breaks thread safety.
Key Takeaways
ObservableObject connects your data model to SwiftUI views by notifying changes automatically.
Mark properties with @Published to trigger UI updates when data changes.
Use @StateObject to create and own ObservableObjects inside views, and @ObservedObject to observe existing ones.
ObservableObject uses Combine publishers under the hood to send change events reactively.
Manual calls to objectWillChange.send() give you fine control over when UI updates happen.