How to avoid adding multiple NSNotification observer?
Solution 1
One way to prevent duplicate observers from being added is to explicitly call removeObserver for the target / selector before adding it again. I imagine you can add this as a category method:
@interface NSNotificationCenter (UniqueNotif)
- (void)addUniqueObserver:(id)observer selector:(SEL)selector name:(NSString *)name object:(id)object {
[[NSNotificationCenter defaultCenter] removeObserver:observer name:name object:object];
[[NSNotificationCenter defaultCenter] addObserver:observer selector:selector name:name object:object];
}
@end
This assumes that the you will only add one unique observer to each target for any notification name, as it will remove any existing observers for that notification name.
Solution 2
Swift 5:
import Foundation
extension NotificationCenter {
func setObserver(_ observer: Any, selector: Selector, name: Notification.Name, object: Any?) {
removeObserver(observer, name: name, object: object)
addObserver(observer, selector: selector, name: name, object: object)
}
}
Swift 3-4:
import Foundation
extension NotificationCenter {
func setObserver(_ observer: AnyObject, selector: Selector, name: NSNotification.Name, object: AnyObject?) {
removeObserver(observer, name: name, object: object)
addObserver(observer, selector: selector, name: name, object: object)
}
}
Swift 2:
import Foundation
extension NSNotificationCenter {
func setObserver(observer: AnyObject, selector: Selector, name: String?, object: AnyObject?) {
removeObserver(observer, name: name, object: object)
addObserver(observer, selector: selector, name: name, object: object)
}
}
Solution 3
The Upvoted answer with extension NotificationCenter { ... }
did not work for me, since my app was creating a new instance of a viewController (this had a Notification observer) every time a notification was posted, so removing an observer on a new instance of a viewController obviously doesn't work.
Previous instances of the viewController that had Notification Observers were getting called.
The below worked for me, since this was removing the Notification Observer as soon as the view was being disappeared.
// Notification observer added
override func viewWillAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(self.someFunc(notification:)), name: Notification.Name("myNotification"), object: nil)
}
// Notification observer removed
override func viewWillDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(self, name: Notification.Name("myNotification"), object: nil)
}
Solution 4
Well should have checked apple documentation.
https://developer.apple.com/documentation/foundation/notificationcenter/1411723-addobserver
let center = NSNotificationCenter.defaultCenter
var tokenOpt: NSObjectProtocol?
tokenOpt = center.addObserverForName("OneTimeNotification", object: nil, queue: nil) { (note) in
print("Received the notification!")
center.removeObserver(token!)
}
So to make sure that the notification is not add if it already existing
if let token = tokenOpt{
center.removeObserver(token)
}
tokenOpt = center.addObserverForName("OneTimeNotification", object: nil, queue: mainQueue) { (note) in
print("Received the notification!")
}
Related videos on Youtube
Boon
I manage a team that builds highly-innovative interactive apps and games for mobile and web. I love building things that reach a lot of people make people happy
Updated on October 21, 2021Comments
-
Boon over 2 years
Right now the API doesn't seem to provide a way to detect if an observer has already been added for a particular NSNotification. What's the best way to avoid adding multiple NSNotification observers other than maintaining a flag on your end to keep track? Has anyone already created a category to facilitate this?
-
jscs about 13 yearsYou're using "observer" and "target" in a very funny, non-standard way here. The "observer" in
addObserver...
indicates the object that will receive a message when the notification is posted, not the method that will make up that message. There's no notion of "target" in notifications. The thing that you're calling a "target" is referred to in the docs as "observer". -
futureelite7 about 13 yearsThe target variable indicates where the runtime should look for the object. I changed the arg name target to observer to remove any potential confusion.
-
XJones about 8 yearsWhile my "you can't answer" may have been too literal (an object cannot detect it's observers) this answer is at best poor practice. Better advice for the OP would be to use a different implementation other than posting and observing notifications for this use case. If a notification is only intended to have a single observer then using a delegate and protocol not only enforces this but makes it clear in the relationship between the object and its delegate.
-
SirRupertIII almost 8 years@XJones This doesn't have to do with a posted notification going out to one and only one observer. This has to do with an observer not observing the same notification twice. With this method you can still have multiple observers to a notification.
-
XJones almost 8 yearsYep, I misunderstood the question. This answer does solve the OP's question but feels a bit like a workaround for the root problem - e.g. why is the object observing the same notification multiple times to begin with?
-
dimpiax over 6 yearsbetter addObserver in
viewDidAppear
instead ofviewWillAppear
. -
Himanshu Moradiya over 6 yearsdid you give me example of add observer using this extension in swift 3.0
-
dimpiax about 4 years@Fattie
removeObserver(self, forKeyPath: tag)
? Where did you find this? -
Dani over 2 years@dimpiax why? Thanks
-
dimpiax over 2 years@DanielSpringer because it's the phase of appearing the view controller, thus, if you're don't have the reasonable case, to place it in
viewWillAppear
(maybe for animation only), it has to be placed in the functionviewDidAppear
, when the view controller is appeared and it's ready to interact with a user.