28

I used to addObserver in viewDidLoad: and removeObserver in dealloc:. Code:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(refreshData)
                                                 name:AnyNotification
                                               object:nil];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:AnyNotification
                                                  object:nil];
}

But according to some articles said, it's better to addObserver in viewDidAppear: and removeObserver in viewDidDisappear:. Code:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(refreshData)
                                                 name:AnyNotification
                                               object:nil];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:AnyNotification
                                                  object:nil];
}

So, what's the better way to addObserver/removeObserver?

fannheyward
  • 18,599
  • 12
  • 71
  • 109
  • It's not good to remove an observer in `dealloc` in case of possible memory warning happening. – Eimantas May 17 '12 at 07:48
  • 1
    In view did disappear, just make sure you remove observer for each specific notification and not removeObserver:self or else you remove the super classes notification observers when the view reappears. – chourobin Sep 10 '12 at 05:25

5 Answers5

27

this depends on your scenario, usually the best approach is to add in viewDidLoad and remove in dealloc and in viewDidUnload (deprecated in iOS 9.0, use dealloc only), but there are some cases when you have same method in different classes like UI effects and want to call only current screen's method using notification, then you will have to add the observer in viewWillAppear and remove it in viewWillDisappear or viewDidAppear/viewDidDisappear

Edit: A note from comments, thanks @honey.

Though now since iOS 9, you no longer need to care about removing the observer. See Apple release notes: "In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated..

Saad
  • 8,857
  • 2
  • 41
  • 51
  • 7
    I think the first solution is not the best because there can be situations when class was inited but the view was not loaded. App will crash with error "Cannot remove an observer for the key path "KEY_PATH" from because it is not registered as an observer." – DanSkeel Aug 03 '13 at 14:08
  • 2
    @DanSkeel maybe add in `init` and `awakeFormNib`? – Puttin Apr 10 '14 at 08:26
  • WHY best to add in `viewDidLoad`, rather than in `viewWillAppear`? I don't see the benefit. I prefer to keep the observer around only while it is needed, so I use `viewWillAppear` and `viewWillDisappear`. Also, those calls seem to be reliably paired. – ToolmakerSteve Sep 07 '16 at 08:34
  • 2
    Well if you need to update some date in rootviewcontroller or any viewcontroller prior to current view controller in stack, your notification will not fired to the previous view controller if you use viewWillAppear/Disappear. As mentioned in Question, it depends on Scenario – Saad Sep 08 '16 at 07:09
  • 4
    @DanSkeel if you have such a scenario where that's possible then it likely means `viewDidLoad` isn't the place you should write the observer. Each business/UI requirement should have its own appropriate cycle. Though now **since iOS 9**, you no longer need to care about removing the observer. See [Apple release notes](https://developer.apple.com/library/content/releasenotes/Foundation/RN-FoundationOlderNotes/index.html): "In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter will no longer send notifications to registered observers that may be deallocated..." – mfaani Sep 25 '17 at 01:13
  • @Saad - thanks, that is a useful point to know. I had not thought about the order that events occur, when considering a view plus the preceding view. – ToolmakerSteve Oct 07 '17 at 02:01
  • Just a friendly note here that viewDidUnload was deprecated in iOS 6. Therefore in more recent code you need to use a different site to balance your Add/Remove observer calls. Indeed, after iOS 9, removeObserver is not always required. – BlueskyMed Apr 14 '19 at 14:10
4

I would normally put it in -viewDidAppear: and -viewDidDisapear: (or -viewWillAppear: and -viewWillDisappear:) simply because in every case I came across I'm only interested in the notification if the view is actually displayed.

It's probably a premature optimisation (your code for handling the notification could take some time, but might be useless if the view is not displayed), but then it's also no more code - it's the same code just in a different method...

Thomas Müller
  • 15,565
  • 6
  • 41
  • 47
  • 1
    This is the correct approach because the view can sometimes be loaded and not immediately appear on screen, like when implementing UIStateRestoring. And you can make use if isMovingToParentViewController inside viewWillAppear to only do things once. – malhal Dec 11 '18 at 18:13
1

Don't forget NSKeyValueObservingOptionInitial. I use it with viewWillAppear/viewWillDisappear so my UI is always up-do-date, even if I hide that view controller, saving resources because I will not update it until is shown again.

Ricardo
  • 2,831
  • 4
  • 29
  • 42
0

-viewWillAppear: + -viewWillDisappear: is better than -viewDidAppear: + -viewDidDisapear:, because they are always called the same number of times.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
wzso
  • 3,482
  • 5
  • 27
  • 48
  • @ToolmakerSteve ,they are paired. – wzso Sep 15 '17 at 02:21
  • @ToolmakerSteve , when navigation controller's `interactivePopGestureRecognizer` is enabled. – wzso Oct 07 '17 at 01:36
  • OK, I understand what you are saying now. I've edited your wording to make it clearer, and upvoted you, as I believe you are making an important point. [Though I'm not currently developing an app, so I can't confirm that the `Did` functions are not always balanced.] (Someone else must have downvoted you, perhaps for the same reason I was confused - couldn't tell what you were saying.) – ToolmakerSteve Oct 07 '17 at 17:11
  • @ToolmakerSteve , (o^^o) I know. But I can't express accurately, because of my poor English writing. – wzso Oct 08 '17 at 08:02
0

The best approach using NSNotifications is adding the observer when you need to observe for notifications and remove them when you don't need them anymore.

This could be on viewDidLoad:, viewWillAppear:, or when the user taps some button etc.

I will give you a little example:

My app has a tabbar, and in some of the view controllers, I'm displaying some info downloaded from internet (a tweet for example). I also have a class pooling for new data from server each 2 minutes, and as the server had new data, I updated the info on database. I will not use a delegate pattern to listen to DB changes, because I have so many view controllers displaying data, and it will be a very bad design making the delegate an array and looping to pass the data for every view controller. So, in this specific scenario, the best to do is to post a notification telling every VC that new data has come.

If your VC removes the delegate when the view disappears, only the current one will receive the notification and update the displaying contents.

You obviously could update the contents of the other VCs before display, on viewWillAppear: for example, but doing this the VC contents will be updated not only when necessary, but each time you change tabs.

It was only one example, where I tried to show you that for NSNotifications, is difficult to advise you when to add or remove observers when we don't have the entire description of how you app behaviours.

FormigaNinja
  • 1,571
  • 1
  • 24
  • 36