ios Objective-C:在哪里删除 NSNotification 的观察者?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6469209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:30:48  来源:igfitidea点击:

Objective-C: Where to remove observer for NSNotification?

objective-ciosnsnotifications

提问by Zhen

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

我有一个客观的C类。在其中,我创建了一个 init 方法并在其中设置了一个 NSNotification

//Set up NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(getData)
                                             name:@"Answer Submitted"
                                           object:nil];

Where do I set the [[NSNotificationCenter defaultCenter] removeObserver:self]in this class? I know that for a UIViewController, I can add it into the viewDidUnloadmethod So what needs to be done if I just created an objective c Class?

我在哪里设置[[NSNotificationCenter defaultCenter] removeObserver:self]这个班级?我知道对于 a UIViewController,我可以将其添加到viewDidUnload方法中 那么如果我只是创建了一个客观的 c 类需要做什么?

回答by Dirk

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 deallocof 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.

我建议您[notificationCenter removeObserver: self]dealloc这些类的方法中添加一个调用,您打算将其用作观察者,因为这是彻底取消注册观察者的最后机会。但是,这只会保护您免受由于通知中心通知死对象而导致的崩溃。当您的对象尚未/不再处于可以正确处理通知的状态时,它无法保护您的代码免受通知。为此......见上文。

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 deallocis 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.

所以,我能提出的最好的一般建议是:保护您的应用程序。针对至少一个可能的失败,在 中removeObserver:跳舞dealloc,因为这是最后一点(在对象的生命中),在那里你可以干净利落地做到这一点。这并不意味着:“只需将删除推迟到dealloc被调用,一切都会好起来的”。相反,一旦对象不再准备(或不需要)接收通知,就移除观察者。那正是正确的时刻。不幸的是,由于不知道上述任何问题的答案,我什至无法猜测那一刻会是什么时候。

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 deallocjust to be sure, but first and foremost: do it at the appropriate moment (which is determined by your use case).

你总是可以安全地removeObserver:多次调用一个对象(除了给定观察者的第一次调用之外,所有的调用都是 nops)。所以:考虑一下(再次)做这件事,dealloc只是为了确定,但首先是:在适当的时候做(这取决于你的用例)。

回答by Paresh Navadiya

Note : This has been tested and working 100% percent

注意:这已经过测试并且工作 100%%

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

目标-C

In iOS 6.0 > version, its better to remove observer in viewWillDisappearas viewDidUnloadmethod is deprecated.

在 中iOS 6.0 > version,最好在viewWillDisappearasviewDidUnload方法中删除观察者已被弃用。

 [[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];


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

很多时候最好是remove observer将视图从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];
    }
}

回答by Sebastian

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

从 iOS 9 开始,不再需要移除观察者。

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

在 OS X 10.11 和 iOS 9.0 中,NSNotificationCenter 和 NSDistributedNotificationCenter 将不再向可能被解除分配的注册观察者发送通知。

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

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

回答by RickiG

If the observer is added to a view controller, I strongly recommend adding it in viewWillAppearand removing it in viewWillDisappear.

如果观察者被添加到视图控制器,我强烈建议viewWillAppearviewWillDisappear.

回答by Legolas

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

回答by Raphael Petegrosso

In general I put it into the deallocmethod.

一般我把它放在dealloc方法中。

回答by Morten Holmgaard

In swift use deinit because dealloc is unavailable:

在 swift 中使用 deinit 因为 dealloc 不可用:

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.

在释放类实例之前立即调用析构器。使用 deinit 关键字编写析构器,类似于使用 init 关键字编写初始化器的方式。析构器仅适用于类类型。

通常,当您的实例被解除分配时,您不需要执行手动清理。但是,当您使用自己的资源时,您可能需要自己执行一些额外的清理工作。例如,如果您创建一个自定义类来打开一个文件并向其中写入一些数据,您可能需要在释放类实例之前关闭该文件。

回答by Ehren

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

*编辑:此建议适用于 iOS <= 5(即使您应该在其中添加viewWillAppear和删除viewWillDisappear- 但是如果出于某种原因您在 中添加了观察者,则该建议适用viewDidLoad

If you've added the observer in viewDidLoadyou should remove it in both deallocand viewDidUnload. Otherwise you'll end up adding it twice when viewDidLoadis called after viewDidUnload(this will happen after a memory warning). This isn't necessary in iOS 6 where viewDidUnloadis deprecated and won't be called (because views are no longer automatically unloaded).

如果你已经添加了观察者,viewDidLoad你应该在dealloc和 中删除它viewDidUnload。否则你最终会在viewDidLoad调用之后添加两次viewDidUnload(这将在内存警告之后发生)。这在 iOS 6 中没有必要,因为viewDidUnload它已被弃用且不会被调用(因为视图不再自动卸载)。

回答by kimimaro

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

在我看来,以下代码在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.

iOS 6 中,删除 中的观察者也没有意义viewDidUnload,因为它现在已被弃用。

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

总而言之,我总是在viewDidDisappear. 但是,这也取决于您的要求,就像@Dirk 所说的那样。

回答by Murat Zazi

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.

首先,addObserver:inviewWillAppear:removeObserver:in的样式viewWillDisappear:对我不起作用(我测试过),因为我在子视图控制器中发布通知以在父视图控制器中执行代码。如果我在同一个视图控制器中发布和监听通知,我只会使用这种风格。

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.

我最依赖的答案是在 iOS 编程:Big Nerd Ranch Guide 4th 中找到的。我相信 BNR 的人,因为他们有 iOS 培训中心,他们不仅仅是在写另一本食谱。准确可能符合他们的最大利益。

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

BNR 示例一:addObserver:in init:, removeObserver:indealloc:

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

BNR 示例二:addObserver:in awakeFromNib:, removeObserver:indealloc:

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

...当删除观察者时,dealloc:他们不使用[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.

我正在更新这篇文章,因为 Apple 现在几乎完全放弃了 Storyboard,所以上面提到的可能不适用于所有情况。重要的是(也是我首先添加这篇文章的原因)是要注意是否viewWillDisappear:有人打电话给您。当应用程序进入后台时,它不适合我。