Objective-C: Where to remove observer for NSNotification?

前端 未结 14 1372
北海茫月
北海茫月 2020-11-29 19:37

I have an objective C class. In it, I created a init method and set up a NSNotification in it

//Set up NSNotification
[[NSNotificationCenter defaultCenter] a         


        
相关标签:
14条回答
  • 2020-11-29 19:50

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

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

    Edit (since the answer seems to draw more comments than I would have thought) All I am trying to say here is: it's really hard to give general advice as to when it's best to remove the observer from the notification center, because 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 I can come up with: to protect your app. against at least one possible failure, do the removeObserver: dance in dealloc, since that's the last point (in the object's life), where you can do that cleanly. What this does not mean is: "just defer the removal until dealloc is called, and everything will be fine". Instead, remove the observer as soon as the object is no longer ready (or required) to receive notifications. That is the exact right moment. Unfortunately, not knowing the answers to any of the questions mentioned above, I cannot even guess, when that moment would be.

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

    0 讨论(0)
  • 2020-11-29 19:52

    In swift use deinit because dealloc is unavailable:

    deinit {
        ...
    }
    

    Swift documentation:

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

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

    0 讨论(0)
  • 2020-11-29 19:54

    Note : This has been tested and working 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 better to remove observer in viewWillDisappear as viewDidUnload method 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];
        }
    }
    
    0 讨论(0)
  • 2020-11-29 19:56

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

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

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

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

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

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

    I hope this helps the next person…

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

    0 讨论(0)
  • 2020-11-29 19:57

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

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

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

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

    0 讨论(0)
  • 2020-11-29 19:57

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

    0 讨论(0)
提交回复
热议问题