Published property wrapper not working on subclass of ObservableObject
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
@Published properties declared in a subclass of an ObservableObject do not trigger SwiftUI view updates because the objectWillChange publisher is synthesized only in the class that declares the ObservableObject conformance — the base class. The subclass's @Published properties silently fail to notify SwiftUI. The fix is to manually call objectWillChange.send() in the subclass, override the property with a willSet observer, or restructure the code to avoid inheritance (use composition or protocols instead).
The Problem
When you tap "Change Child", the view does not update even though childValue changed.
Why This Happens
Swift synthesizes the objectWillChange publisher (a PassthroughSubject<Void, Never>) in the class that declares ObservableObject conformance. The compiler generates willSet observers for @Published properties in that class to call objectWillChange.send(). Subclass @Published properties create their own internal Publisher, but they do not hook into the parent's objectWillChange. SwiftUI listens to objectWillChange — not the individual @Published publishers — so subclass changes are invisible.
Fix 1: Manual objectWillChange.send()
Call the publisher explicitly using willSet or a custom setter:
Or using a computed property backed by a private stored property:
Fix 2: Use Combine to Forward Changes
Subscribe to the subclass's published property and forward to objectWillChange:
This approach works but adds boilerplate for every @Published property in the subclass.
Fix 3: Avoid Inheritance — Use Composition
The cleanest solution is to avoid subclassing ObservableObject entirely:
Fix 4: Protocol-Based Approach
Use protocols instead of class inheritance:
Since ChildViewModel directly conforms to ObservableObject, all its @Published properties work correctly.
Fix 5: @Observable Macro (iOS 17+)
The @Observable macro (Observation framework) fixes this issue entirely:
The @Observable macro tracks property access at the individual property level rather than relying on objectWillChange, so subclass properties work correctly.
Common Pitfalls
- Assuming
@Publishedworks in all subclasses:@Publishedonly triggersobjectWillChange.send()in the class that declaresObservableObjectconformance. Every subclass level needs its own mechanism to notify the publisher. This is a well-known limitation of the Combine-based observation system. - Using
didSetinstead ofwillSet: SwiftUI reads the new value during theobjectWillChangenotification. If you callobjectWillChange.send()indidSet, the value has already changed but SwiftUI may have already captured the old state. UsewillSetto send the notification before the change. - Forgetting
[weak self]in Combine subscriptions: In Fix 2, omitting[weak self]in thesinkclosure creates a retain cycle between the view model and its cancellable set. Always use weak references in Combine subscribers. - Multiple inheritance levels compounding the issue: If you have
Base -> Middle -> Child, each level needs its own forwarding. The problem gets worse with deeper hierarchies. Prefer composition or the@Observablemacro for complex view model hierarchies. - Mixing
@ObservableandObservableObject: You cannot use both@ObservableandObservableObjecton the same class. If the base class usesObservableObject, the subclass cannot use@Observable— you must migrate the entire hierarchy to one system or the other.
Summary
@Publishedin subclasses ofObservableObjectdoes not trigger view updates becauseobjectWillChangeis synthesized only in the conforming base class- Quick fix: use
willSet { objectWillChange.send() }on subclass properties instead of@Published - Better fix: use composition instead of inheritance for
ObservableObjectclasses - Best fix (iOS 17+): migrate to the
@Observablemacro, which handles subclass properties correctly - Avoid deep
ObservableObjecthierarchies — they compound the forwarding problem at each level
Related reading
- Pull to refresh UITableView without UITableViewController
- Push Notifications in Android Platform
- Putting a LazyVStack or LazyHStack in a ScrollView causes stuttering
- R cannot be resolved - Android error
- R cannot be resolved - Android error
- R cannot be resolved to a variable?
- RCTBundleURLProvider.h file not found - AppDelegate.m
- React-Native Error Failed to install CocoaPods dependencies for iOS project, which is required by this template
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.