[ACCEPTED]-Objective-C: Where to remove observer for NSNotification?-nsnotifications

Accepted answer
Score: 112

The generic answer would be "as soon as 35 you no longer need the notifications". This 34 is obviously not a satisfying answer.

I'd 33 recommend, that you add a call [notificationCenter removeObserver: self] in method 32 dealloc of those classes, which you intend to use 31 as observers, as it is the last chance to 30 unregister an observer cleanly. This will, however, only 29 protect you against crashes due to the notification 28 center notifying dead objects. It cannot 27 protect your code against receiving notifications, when 26 your objects are not yet/no longer in a 25 state in which they can properly handle 24 the notification. For this... See above.

Edit (since 23 the answer seems to draw more comments than 22 I would have thought) All I am trying to 21 say here is: it's really hard to give general 20 advice as to when it's best to remove the 19 observer from the notification center, because 18 that depends:

  • On your use case (Which notifications are observed? When do they get send?)
  • The implementation of the observer (When is it ready to receive notifications? When is it no longer ready?)
  • The intended life-time of the observer (Is it tied to some other object, say, a view or view controller?)
  • ...

So, the best general advice 17 I can come up with: to protect your app. against 16 at least one possible failure, do the removeObserver: dance 15 in dealloc, since that's the last point (in the 14 object's life), where you can do that cleanly. What 13 this does not mean is: "just defer the removal 12 until dealloc is called, and everything will be 11 fine". Instead, remove the observer as soon as the object is no longer ready (or required) to receive notifications. That 10 is the exact right moment. Unfortunately, not 9 knowing the answers to any of the questions 8 mentioned above, I cannot even guess, when 7 that moment would be.

You can always safely 6 removeObserver: an object multiple times (and all but the 5 very first call with a given observer will 4 be nops). So: think about doing it (again) in 3 dealloc just to be sure, but first and foremost: do 2 it at the appropriate moment (which is determined 1 by your use case).

Score: 39

Note : This has been tested and working 3 100% percent

Swift

override func viewWillDisappear(animated: Bool){
    super.viewWillDisappear(animated)
    
    if self.navigationController!.viewControllers.contains(self) == false  //any other hierarchy compare if it contains self or not
    {
        // the view has been removed from the navigation stack or hierarchy, back is probably the cause
        // this will be slow with a large stack however.
        
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

PresentedViewController:

override func viewWillDisappear(animated: Bool){
    super.viewWillDisappear(animated)
    
    if self.isBeingDismissed()  //presented view controller
    {
        // remove observer here
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

Objective-C

In iOS 6.0 > version , its 2 better to remove observer in viewWillDisappear as viewDidUnload method 1 is deprecated.

 [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];

There is many times its better to remove observer when the view has been removed from the navigation stack or hierarchy.

- (void)viewWillDisappear:(BOOL)animated{
 if (![[self.navigationController viewControllers] containsObject: self]) //any other hierarchy compare if it contains self or not
    {
        // the view has been removed from the navigation stack or hierarchy, back is probably the cause
        // this will be slow with a large stack however.
        
        [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
    }
}

PresentedViewController:

- (void)viewWillDisappear:(BOOL)animated{
    if ([self isBeingDismissed] == YES) ///presented view controller
    {
        // remove observer here
        [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
    }
}
Score: 39

Since iOS 9 it's no longer necessary to 4 remove observers.

In OS X 10.11 and iOS 9.0 3 NSNotificationCenter and NSDistributedNotificationCenter 2 will no longer send notifications to registered 1 observers that may be deallocated.

https://developer.apple.com/library/mac/releasenotes/Foundation/RN-Foundation/index.html#10_11NotificationCenter

Score: 25

If the observer is added to a view controller, I strongly 2 recommend adding it in viewWillAppear and removing it 1 in viewWillDisappear.

Score: 20
-(void) dealloc {
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      [super dealloc];
}

0

Score: 7

In general I put it into the dealloc method.

0

Score: 6

In swift use deinit because dealloc is unavailable:

deinit {
    ...
}

Swift 14 documentation:

A deinitializer is called 13 immediately before a class instance is deallocated. You 12 write deinitializers with the deinit keyword, similar to 11 how intializers are written with the init 10 keyword. Deinitializers are only available 9 on class types.

Typically you don’t need 8 to perform manual clean-up when your instances 7 are deallocated. However, when you are working 6 with your own resources, you might need 5 to perform some additional clean-up yourself. For 4 example, if you create a custom class to 3 open a file and write some data to it, you 2 might need to close the file before the class 1 instance is deallocated.

Score: 5

*edit: This advice applies to iOS <= 5 11 (even there you should be adding in viewWillAppear and 10 removing in viewWillDisappear - however the advice applies 9 if for some reason you've added the observer 8 in viewDidLoad)

If you've added the observer in viewDidLoad you 7 should remove it in both dealloc and viewDidUnload. Otherwise 6 you'll end up adding it twice when viewDidLoad is called 5 after viewDidUnload (this will happen after a memory 4 warning). This isn't necessary in iOS 6 3 where viewDidUnload is deprecated and won't be called 2 (because views are no longer automatically 1 unloaded).

Score: 5

In my opinion, the following code makes 5 no sense in ARC:

- (void)dealloc
{
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      [super dealloc];
}

In iOS 6, there's also no sense 4 in removing observers in viewDidUnload, because it has 3 been deprecated now.

To sum up, I always 2 do it in viewDidDisappear. However, it depends on your requirements 1 also, just like @Dirk said.

Score: 4

I think I found a reliable answer! I had to, as the answers 25 above are ambiguous and seem contradicting. I 24 looked through Cookbooks and Programming 23 Guides.

First, the style of addObserver: in viewWillAppear: and removeObserver: in 22 viewWillDisappear: does not work for me (I tested it) because 21 I am posting a notification in a child view 20 controller to execute code in the parent 19 view controller. I would only use this style 18 if I was posting and listening for the notification 17 within the same view controller.

The answer 16 I will rely on the most, I found in the 15 iOS Programming: Big Nerd Ranch Guide 4th. I 14 trust the BNR guys because they have iOS 13 training centers and they are not just writing 12 another cookbook. It is probably in their 11 best interest to be accurate.

BNR example 10 one: addObserver: in init:, removeObserver: in dealloc:

BNR example two: addObserver: in awakeFromNib:, removeObserver: in 9 dealloc:

…when removing observer in dealloc: they don’t use 8 [super dealloc];

I hope this helps the next person…

I am updating 7 this post because Apple now has almost completely 6 gone with Storyboards so the above mentioned 5 may not apply to all situations. The important 4 thing (and the reason I added this post 3 in the first place) is to pay attention 2 if your viewWillDisappear: is getting called. It wasn't for 1 me when the application entered background.

Score: 2

The accepted answer is not safe and could 5 cause a memory leak. Please do leave the 4 unregister in dealloc but also deregister 3 in viewWillDisappear (that is of course 2 if you register in viewWillAppear)....THAT'S 1 WHAT I DID ANYWAYS AND IT WORKS GREAT! :)

Score: 1

It is important to notice also that viewWillDisappear is 19 called also when the view controller present 18 a new UIView. This delegate simply indicate 17 that the view controller main view is not 16 visible on the display.

In this case, deallocating 15 the notification in viewWillDisappear may be inconvenient 14 if we are using the notification to allow 13 the UIview to communicate with the parent 12 view controller.

As a solution I usually 11 remove the observer in one of these two 10 methods:

- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"viewController will disappear");
    if ([self isBeingDismissed]) {
        NSLog(@"viewController is being dismissed");
        [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
    }
}

-(void)dealloc {
    NSLog(@"viewController is being deallocated");
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
}

For similar reasons, when I issue 9 the notification the first time, I need 8 to account for the fact that any time a 7 view with appear above the controller then 6 viewWillAppear method is fired. This will in turn generate 5 multiple copy of the same notification. Since 4 there isn't a way to check if a notification 3 is already active, I obviate the problem 2 by removing the notification before adding 1 it:

- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"viewController will appear");
    // Add observers
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"imageGenerated" object:nil]; // This is added to avoid duplicate notifications when the view is presented again
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedImageFromCameraOrPhotolibraryMethodOnListener:) name:@"actionCompleted" object:nil];

}
Score: 0
override func viewDidLoad() {   //add observer
  super.viewDidLoad()
  NotificationCenter.default.addObserver(self, selector:#selector(Yourclassname.method), name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}

override func viewWillDisappear(_ animated: Bool) {    //remove observer
    super.viewWillDisappear(true)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}

0

More Related questions