Warning for iOS/iPhone users about duplicate NSNotification observations
Asked Answered
A

3

21

This isn't a question so much as a warning to others to save them some time.

NSNotificationCenter on iOS 3/iPhone OS 3 (I'm assuming also Mac OS X and iOS 4) has the following behavior:

If you register yourself multiple times for the exact specific notification, NSNotificationCenter will NOT recognize the redundancy and instead will fire off as many notifications to you as you've registered an observation for.

This is almost never the behavior you want to see and is almost always accidental.

Example:

I want my view controller to receive notifications from a singleton network object when new data comes in:

- (void) viewDidLoad 
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(newDataArrived:) 
                name:NewDataArrivedNotification
              object:[NetworkListener sharedNetworkListener]];
}

but earlier I'd already put the same thing in viewWillAppear:

- (void) viewWillAppear
{
    [super viewWillAppear];

    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(newDataArrived:)
                name:NewDataArrivedNotification
              object:[NetworkListener sharedNetworkListener]];
}

Note that it's exactly the same notification, resolving to the same observer, sender and notification name.

In this case, if I don't remove one of those addObserver calls, I'll get duplicate notifications to my view controller.

In a multi-threaded environment, this is a world of hurt. Trust me.

Just putting this out there in case there are others who run into something like this.

Accuracy answered 18/6, 2010 at 20:22 Comment(2)
Good to have the warning - you should probably put most of this in an answer and accept it :) (cue Alex Trebek mumbling something about 'must phrase your answer…')Syllabic
Took me long enough, but done.Accuracy
A
2

NSNotificationCenter on iOS 3/iPhone OS 3 (I'm assuming also Mac OS X and iOS 4) has the following behavior:

If you register yourself multiple times for the exact specific notification, NSNotificationCenter will NOT recognize the redundancy and instead will fire off as many notifications to you as you've registered an observation for.

This is almost never the behavior you want to see and is almost always accidental.

Example:

I want my view controller to receive notifications from a singleton network object when new data comes in:

- (void) viewDidLoad 
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(newDataArrived:) 
                name:NewDataArrivedNotification
              object:[NetworkListener sharedNetworkListener]];
}

but earlier I'd already put the same thing in viewWillAppear:

- (void) viewWillAppear
{
    [super viewWillAppear];

    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(newDataArrived:)
                name:NewDataArrivedNotification
              object:[NetworkListener sharedNetworkListener]];
}

Note that it's exactly the same notification, resolving to the same observer, sender and notification name.

In this case, if I don't remove one of those addObserver calls, I'll get duplicate notifications to my view controller.

In a multi-threaded environment, this is a world of hurt. Trust me.

Just putting this out there in case there are others who run into something like this.

Accuracy answered 21/4, 2013 at 2:18 Comment(2)
This is a coder error, not a library error. Only register for the notifications you want to receive. I am not sure why you would register in the same object multiple times for the same notification.Latish
in situations where you have a base view controller which has an observer and some other view controllers extend that base class, then if the code for adding the observer is in the view lifecycle methods like viewDidLoad or viewDidAppear, a way to avoid the observers being added to the Dispatch Table is by removing the observer and then adding it in view did load. This way the observer will not be added multiple times.Graben
B
2

You should and always clean up your observers.
The easiest way to do it is : [[NSNotificationCenter defaultCenter] removeObserver:self]
viewDidLoad is not a good place to add observers, because this functions may get called multiple times, this happens when viewDidUnload is triggered. A good place to put your addObservers in viewWillAppear, and removeObservers in viewWillDisappear.

Basically answered 24/1, 2013 at 7:31 Comment(1)
also, viewDidUnload is deprecated and no longer even called in iOS 6Accuracy
A
2

NSNotificationCenter on iOS 3/iPhone OS 3 (I'm assuming also Mac OS X and iOS 4) has the following behavior:

If you register yourself multiple times for the exact specific notification, NSNotificationCenter will NOT recognize the redundancy and instead will fire off as many notifications to you as you've registered an observation for.

This is almost never the behavior you want to see and is almost always accidental.

Example:

I want my view controller to receive notifications from a singleton network object when new data comes in:

- (void) viewDidLoad 
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(newDataArrived:) 
                name:NewDataArrivedNotification
              object:[NetworkListener sharedNetworkListener]];
}

but earlier I'd already put the same thing in viewWillAppear:

- (void) viewWillAppear
{
    [super viewWillAppear];

    [[NSNotificationCenter defaultCenter] addObserver:self
            selector:@selector(newDataArrived:)
                name:NewDataArrivedNotification
              object:[NetworkListener sharedNetworkListener]];
}

Note that it's exactly the same notification, resolving to the same observer, sender and notification name.

In this case, if I don't remove one of those addObserver calls, I'll get duplicate notifications to my view controller.

In a multi-threaded environment, this is a world of hurt. Trust me.

Just putting this out there in case there are others who run into something like this.

Accuracy answered 21/4, 2013 at 2:18 Comment(2)
This is a coder error, not a library error. Only register for the notifications you want to receive. I am not sure why you would register in the same object multiple times for the same notification.Latish
in situations where you have a base view controller which has an observer and some other view controllers extend that base class, then if the code for adding the observer is in the view lifecycle methods like viewDidLoad or viewDidAppear, a way to avoid the observers being added to the Dispatch Table is by removing the observer and then adding it in view did load. This way the observer will not be added multiple times.Graben
K
0

As you said yourself, NSNotificationCenter makes no check for duplicates, which may be annoying for some, but makes sense when concidering the full system behind it.

The same logic applies to adding targets to certain objects, but there is often a key recognition on those.

Thank you for the insight, and for a good, SEO-friendly warning :)

Krute answered 29/12, 2012 at 10:43 Comment(1)
Consider the full system behind it, it makes sense? Could you please tell more detail? Thanks.Janellajanelle

© 2022 - 2024 — McMap. All rights reserved.