Observer <object> was not registered as an observer – duplicate removeObserver call
0 reputation · 17 Jun 2023, 09:42 UTC
0 reputation · 17 Jun 2023, 09:42 UTC
When developing with Foundation’s NSNotificationCenter, developers often need to clean up observers in deinit or cleanup routines. Calling removeObserver:name:object: on an object that has already been removed, or never added, raises an NSInvalidArgumentException with the message “Observer was not registered as an observer”. The decision point is whether to add a defensive check before each removal or to let the exception propagate and handle it elsewhere.
Considerations include the impact on performance, the desire to keep crash‑free logs, and the lack of a built‑in method to query an observer’s registration state. The framework documentation does not prescribe a standard pattern, leaving the choice to individual projects.
What are the recommended strategies to avoid this exception without introducing unnecessary overhead? Is it acceptable to wrap the call in a try/catch block, or should a custom registration tracker be maintained? How do other Apple frameworks handle similar cleanup scenarios?
32275 reputation · 17 Jun 2023, 10:51 UTC
The exception is thrown when removeObserver:name:object: (or the variant with a specific name/object) is invoked for an observer that is either never registered via addObserver or has already been removed. The notification center searches its internal list; if the observer entry is not found it raises NSInvalidArgumentException with the message “Observer was not registered as an observer”.
removeObserver will raise an exception if the observer is not registered for the given name/object combination.removeObserver(_:) (i.e., remove the observer from all notifications) does **not** raise an exception when the observer has no registrations; it simply does nothing.deinit (or your cleanup routine):
deinit {
NotificationCenter.default.removeObserver(self)
}
This safely clears any registrations without risking the exception, regardless of how many (or zero) observers were added.
addObserver call succeeded. Only call removeObserver:name:object: when the flag indicates the observer is currently registered.
If you are using the specific removeObserver:name:object: form and cannot change to the blanket removal, confirm whether you are observing the same notification name and object each time. Knowing whether the name/object pair is constant will determine if a single flag is sufficient or if you need a more granular tracking structure.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 17 Jun 2023, 21:05 UTC
removeObserver(_:) is safe to call multiple times, it's important to distinguish it from removeObserver(_:name:object:), which throws an NSInvalidArgumentException if the specific pairing isn't registered. Since Foundation doesn't provide a public API to query an observer's state, the most performant strategy is to maintain a local Set or boolean flag within your class to track active registrations. This avoids the heavy overhead of try/catch blocks—which are expensive and discouraged for flow control. Additionally, note that since iOS 9 and macOS 10.11, the system handles deallocated observers more gracefully in some contexts, but explicit name-object removals still require defensive tracking to prevent crashes during complex cleanup.