Why is my NSNotification its observer called multiple times?
Asked Answered
H

5

30

Within an App I make use of several viewcontrollers. On one viewcontroller an observer is initialized as follows:

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"MyNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myMethod:) name:@"MyNotification" object:nil];

Even when removing the NSNotification before initializing the number of executions of myMethod: is being summed up by the amount of repeated views on the respective viewcontroller.

Why does this happen and how can I avoid myMethod: being called more then once.

Note: I made sure by using breakpoints that I did not made mistakes on calling postNotification multiple times.

Edit: This is how my postNotification looks like

NSArray * objects = [NSArray arrayWithObjects:[NSNumber numberWithInt:number],someText, nil];
NSArray * keys = [NSArray arrayWithObjects:@"Number",@"Text", nil];
NSDictionary * userInfo = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
[[NSNotificationCenter defaultCenter] postNotificationName:@"myNotification" object:self userInfo:userInfo];

edit: even after moving my subscribing to viewwillappear: I get the same result. myMethod: is called multiple times. (number of times i reload the viewcontroller).

-(void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"MyNotification" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myMethod:) name:@"MyNotification" object:nil];
}

edit: something seems wrong with my lifecycle. ViewDidUnload and dealloc are not getting called, however viewdiddisappear is getting called.

The way I push my Viewcontroller to the stack is as follows where parent is a tableview subclass (on clicking the row this viewcontroller is initiated:

detailScreen * screen = [[detailScreen alloc] initWithContentID:ID andFullContentArray:fullContentIndex andParent:parent];
[self.navigationController pushViewController:screen animated:YES];

Solution:

Moving removal of nsnotification to viewdiddisappear did the trick. Thanks for guidance!

Heartburn answered 6/11, 2013 at 0:11 Comment(3)
your solution is working for me thanq....Blizzard
@Heartburn thnx solution : helpedKarlakarlan
Another thing I've somehow done, that will cause a similar issue, is declared NSString * const ABCSomeNotification twice...Scudder
G
42

Based on this description, a likely cause is that your viewcontrollers are over-retained and not released when you think they are. This is quite common even with ARC if things are over-retained. So, you think that you have only one instance of a given viewcontroller active, whereas you actually have several live instances, and they all listen to the notifications.

If I was in this situation, I would put a breakpoint in the viewcontroller’s dealloc method and make sure it is deallocated correctly, if that’s the intended design of your app.

Garnierite answered 6/11, 2013 at 0:58 Comment(4)
Indeed my viewDidUnload and dealloc method are not getting called. Still I do net get why. (edited my question)Heartburn
You should also removeObserver:self in the view controller’s dealloc method if you are not doing that. Otherwise, the NSNotificationCenter will retain the view controller, and it never gets deallocated.Garnierite
BTW, viewDidUnload only works < ios 6. So, don't expect that to fire if you're using anything > 5.Skees
I don't know reference removed or not but in back button I am doing self.navigationController.popToRootViewController(animated : true). My Observer is calling multiple time. Can you please explain me.?Edp
S
39

In which methods did you register the observers?

Apple recommends that observers should be registered in viewWillAppear: and unregistered in viewWillDissapear:

Are you sure that you don't register the observer twice?

Syntax answered 6/11, 2013 at 0:25 Comment(2)
I initialize it within the initWith: startup methodHeartburn
@Heartburn I wouldn't add it to the startup method. 2 reasons: 1) self might not be formed correctly and 2) it might never make it on screen in which case you probably don't want to add your notification.Skees
B
5

Ran into this issue in an application running swift. The application got the notification once when first launched. the notification increases the number of times you go into the background and come back. i.e

  • app launches one - add observer gets gets called once in view will appear or view did load - notification is called once
  • app goes into background and comes back, add observer gets called again in view will appear or view did load. notification gets called twice.
  • the number increases the number of times you go into background and come back.
  • code in view will disappear will make no difference as the view is still in the window stack and has not been removed from it.

solution: observe application will resign active in your view controller:

  NSNotificationCenter.defaultCenter().addObserver(self, selector: "applicationWillResign:", name: UIApplicationWillResignActiveNotification, object: nil)

  func applicationWillResign(notification : NSNotification) {
    NSNotificationCenter.defaultCenter().removeObserver(self)
  }

this will make sure that your view controller will remove the observer for the notification when the view goes into background.

Brilliancy answered 3/2, 2015 at 1:26 Comment(0)
P
1

it is quite possible you are subscribing to the notifications

[[NSNotificationCenter defaultCenter] postNotificationName:@"myNotification" object:self userInfo:userInfo];

before self gets initialized. And trying to unsubscribe 'self' which isn't really subscribed to, and you will get all global myNotification notifications.

If your view was hooked up in IB, use -awakeFromNib: as the starting point to register for notifications

Phip answered 6/11, 2013 at 0:43 Comment(0)
K
0

It is possible that the class with the observer is, quite appropriately, instantiated multiple times. When you are debugging it will kinda look like the notification is being posted multiple times. But if you inspect self you might see that each time is for a different instance.

This could easily be the case if your app uses a tab bar and the observer is in a base class of which your view controllers are subclasses.

Kos answered 8/11, 2019 at 19:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.