Where to remove observer for NSNotification in Swift?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Notification observer cleanup in Swift depends on observer lifetime, not a single universal method call location. Removing too early misses events, and removing too late causes duplicate callbacks or retained objects. The right strategy is choosing lifecycle scope first, then matching add and remove points consistently.
Decide Observer Lifetime Before Coding
Ask this first: how long should this object observe events.
Common lifetimes:
- Whole object lifetime, such as service objects and long-lived controllers.
- Visible-screen lifetime, such as view-only refresh events.
- Temporary task lifetime, such as one-shot operation listeners.
Observer removal location follows this decision.
Selector-Based Observer for Object Lifetime
For selector API observers intended to live with object, add in setup and remove in deinit.
This keeps observer lifetime aligned with object lifetime.
Visible-Screen Scope Pattern
If callbacks are relevant only while screen is visible, pair add and remove in view lifecycle.
This prevents off-screen views from processing UI updates.
Block-Based Observer Requires Token Removal
Closure-based API returns a token object. Remove by token, not by self.
Forgetting token removal can keep callbacks alive unexpectedly.
Avoid Duplicate Registration
A common bug is adding observers repeatedly in lifecycle methods without symmetric removal. Symptoms include callback firing multiple times per event.
Prevention options:
- Strict add-remove symmetry.
- Registration flag for idempotent setup.
- Centralized observer setup in one method.
Structured lifecycle design prevents this class of bugs.
Threading and Capture Safety
Notifications may be delivered on posting thread. If callback updates UI, ensure execution on main thread.
In block observers, capture self weakly to avoid retain cycles in long-lived notifications.
Correct thread and capture handling matters as much as remove timing.
Targeted Removal Versus Global Removal
If object listens to several notifications, targeted removal is safer than removing all observers blindly.
Use global removal only when object is truly done with all notifications.
Testing Observer Lifecycle
Add tests and diagnostics for:
- callback fires once per event.
- callback stops after deallocation.
- no duplicate callbacks after repeated appear/disappear cycles.
- no retained observer tokens.
Lifecycle-focused tests catch these bugs earlier than manual UI checks.
Common Pitfalls
- Using one removal strategy for every observer type. Fix by matching cleanup to observer API and intended lifetime.
- Forgetting to remove block-observer tokens. Fix by storing token and removing it in
deinit. - Adding observers repeatedly in
viewWillAppearwithout matching remove. Fix with symmetric lifecycle hooks. - Updating UI from non-main thread notification callbacks. Fix by dispatching UI work to main queue.
- Capturing
selfstrongly in long-lived closure observers. Fix with weak capture and explicit lifetime control.
Summary
- Observer removal location should follow intended observation lifetime.
- Selector-based observers are commonly removed in
deinit. - Visibility-scoped observers should be added and removed with view appearance lifecycle.
- Block-based observers require token-based cleanup.
- Consistent lifecycle design prevents duplicates, leaks, and stale callbacks.

