How to stop the Observer in NSNotification to called twice?

38,513

Solution 1

Solution 1: The first thing is to check if the notification itself is posted twice.

Solution 2: Even if the notification is posted only once, the action will be called as many times you've added the observer for the notification (no matter the notification is same or not). For example, the following two lines will register the observer(self) for the same notification(aSelector) twice.

[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];

You have to find where you are adding observer for the second time, and remove it. And also make sure that the code where you are add the observer is not called twice.

Solution 3: If you are not sure whether you have already added the observer or not, you can simply do the following. This will make sure that the observer is added only once.

[[NSNotificationCenter defaultCenter] removeObserver:self name:aName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];

Solution 2

If your addObserver method is run multiple times, it will create multiple observers. My issue was that I somehow placed my observer in viewWillAppear which appeared multiple times before I posted the notification and it resulted in my observer being called multiple times.

While EmptyStack's 3rd solution works, there is a reason your observer is being called twice, so by finding it, you can prevent needless lines of code instead of removing and adding the same observer.

I would suggest putting your observer in viewDidLoad to avoid simple errors like the one I experienced.

Solution 3

Try to removeObserver in viewWillDisappear method :

-(void)viewWillDisappear:(BOOL)animated{

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"startAnimating" object:nil]; }

Solution 4

Try set a breakpoint on [[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil]; and check if it is called more than once.

Solution 5

For those looking for a solution in Swift 2.2 and above and who have reached this question like me you can create an extension as follows :

import Foundation

extension NSNotificationCenter {
  func setObserver(observer: AnyObject, selector: Selector, name: String?, object: AnyObject?) {
    NSNotificationCenter.defaultCenter().removeObserver(observer, name: name, object: object)
    NSNotificationCenter.defaultCenter().addObserver(observer, selector: selector, name: name, object: object)
  }
}

You can call this method as follows :

NSNotificationCenter.defaultCenter().setObserver(self, selector: #selector(methodName), name: "name", object: nil)

The extension will handle the removal of previous observer if it exists. Even if there was no previous observer present this code won't crash.

Share:
38,513
Azhar
Author by

Azhar

.net / iOS / Android / Windows Mobile/ React-native Optimization Optimization Optimization

Updated on July 08, 2022

Comments

  • Azhar
    Azhar almost 2 years

    I have an observer of NSNotification which is called twice. I do not know what to do with it.

    I googled it but no solution found.

    [[NSNotificationCenter defaultCenter] addObserver:self
         selector:@selector(connectedToServer:) name:@"ConnectedToServer" object:nil];
    
    - (void)connectedToServer:(NSNotification*)notification {
    
        [[NSNotificationCenter defaultCenter] postNotificationName:@"SendMessageToServer" object:message];
    }
    
  • brigadir
    brigadir over 12 years
    Maybe you receive the notification two times. To check it set breakpoint in aSelector and look at calling stack.
  • SamehDos
    SamehDos over 12 years
    [[NSNotificationCenter defaultCenter] removeObserver:self name:aName object:nil]; is the best answer
  • toblerpwn
    toblerpwn over 11 years
    As with Azhar, I could not resolve this issue using the methods above. Not sure what was going on - but in my case I switched to using a delegate for my callback needs. This is not a solution for all cases, but a workaround that may help some future readers who are also stuck.
  • RyanG
    RyanG about 11 years
    Wow I was debugging this for way too long... I was calling addObserver at the beginning of a function and not removing it correctly.. hence my function being called multiple times. Added the remove above it and works perfect.
  • Ashwin G
    Ashwin G about 10 years
    This is probably the solution. A breakpoint can be kept in the addObserver method to check how many times this same observer has been added.
  • H.Rabiee
    H.Rabiee over 9 years
    if you're registering the observer in one of your nib init methods then it's most likely being called (and registered) more than once.
  • Maverick1st
    Maverick1st about 9 years
    If i read this a few hours before i would have saved sooo much time. just couldn't figure out, why multiple observers where registered. Now moved the registration from viewWillAppear to viewDidLoad and it works like a charm. Thx a lot.
  • Bhavin Ramani
    Bhavin Ramani over 8 years
    I got solution from solution 3. I have implement this method [NSNotificationCenter defaultCenter] in view did load and view did load was called two times in class.
  • olha
    olha almost 8 years
    Solution 2 rocks, because I add notification once in awakeFromNib, and awakeFromNib is called twice.
  • ToolmakerSteve
    ToolmakerSteve almost 8 years
    addObserver in viewWillAppear works fine, if you add the corresponding removeObserver in viewWillDisappear, as suggested by bhadresh! (Which you should do anyway - no reason to have unnecessary observers hanging around.) If you put addObserver in viewDidLoad, then where do you put removeObserver? Do you really want the observer hanging around after your view is not being seen?
  • RamaKrishna Chunduri
    RamaKrishna Chunduri almost 8 years
    use GCD and dispatch once to ensure observer is added only once. static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //add observer code });
  • Cian
    Cian over 7 years
    Using this way, if the self(i.e. a UIViewcontroller) is allocated again and again, every new object of self would create an observer. Using above code would only remove the current self's observer but not the old self's observer. Have faced this issue before.
  • Jonny
    Jonny about 7 years
    In my case viewDidLoad was called twice, unexpectedly. Do not rely on viewDidLoad being called only once. I mean I do, but this was the culprit this time.
  • OxyFlax
    OxyFlax over 6 years
    @Jonny How did you solve the problem? That's my case, viewDidLoad, ViewWillAppear are called twice and at the same time so delete the notification before adding it doesn't solve the problem...
  • Jonny
    Jonny over 6 years
    @OxyFlax I don't remember what I was working on. But normally doing addObserver using NotificationCenter in viewDidLoad should be correct... For NC I no longer use removeObserver at all, since iOS 9 - see the docs under discussion: developer.apple.com/documentation/foundation/…
  • bruce1337
    bruce1337 over 6 years
    Just to note that there are many answers elsewhere for questions like "Why was viewDidLoad() called twice?" – and they all emphasize that there is no guarantee that viewDidLoad will only be called once. It would seem that performing removeObserver before addObserver is the way to go.
  • Jack
    Jack about 6 years
    @Azhar have you found any solution ?
  • Paul Bruneau
    Paul Bruneau over 2 years
    I also had viewdidLoad getting called repeatedly, occasionally. Makes sense. I put the addobserver call in init. If you can't do that, you can wrap it in a dispatch_once as suggested above