Quick iOS tip: where is the right place to add and remove observers in UIViewControllers?

While I was debugging my iPhone app I noticed (thanks to my verbose logs) that certain methods were called multiple times… apparently like if they were in a loop. I lost several time trying to figure out why and then I realized that the problem was related to defining them in the wrong place! (technically not wrong at all, but definitely wrong in my app context).
I was adding listeners in viewDidLoad and removing them in viewDidUnload.
This is acceptable only if you have simple UIViewControllers that don’t work in composite controllers hierarchy (they are not contained in UINavigationController or UITabBarController).
viewDidLoad is called after the view controller’s view has been released, but in a controllers hierarchy this does not happen since controllers are retained by the container! This leads to multiple messages dispatched to registered observers, so if you have a UINavigationController containing a sequence of 5 viewController, handlers will be triggered 5 times (one for each controller).
The safely approach to add and remove listeners is instead in viewWillAppear: and viewWillDisappear:
Example:

- (void)viewWillAppear:(BOOL)animated
{
   [super viewWillAppear:animated];
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(foo:) name:UIKeyboardDidShowNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
   [super viewWillDisappear:animated];
   [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
}
  • Unless, of course, some of the off-screen view controllers need to be notified as well (e.g., to update their data model members).

    I haven’t come across the same problem as you in the apps I made so far. I’ve always registered on -init and unregistered on -dealloc.

  • Binh Nguyen

    In case you need the notification callbacks to still be fired if the view is off-screen, check my answer here:

    http://stackoverflow.com/questions/8372841/removing-a-nsnotificationcenter-observer-in-ios-5-arc/12381001#12381001

  • Oberdan

    I think the better place to remove observers is in dealloc methods.

  • Binh Nguyen

    Sometimes, dealloc() is not called, especially with ARC

  • Oberdan

    Ohh, this certainly could be a problem.
    Thanks, I’ll look forward to ivestigate if this behavior is ocurring on my apps.

  • If you use app run in background and have tabar. It will not run to viewWillAppear after app come back from foreground. So, It don’t add observer. You will be crash when remove nil observer :)