ios 在 UIViewController 中向 NSNotificationCenter 添加和删除观察者

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10333153/
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 18:05:38  来源:igfitidea点击:

Adding and removing observers to NSNotificationCenter in a UIViewController

objective-ciosdeallocnsnotificationcenteraddobserver

提问by Undistraction

Looking at various Apple examples (for example Add Music) in which I see they add observers to the default NSNotificationCenterin viewDidLoad, then remove them in dealloc. This seems dangerous as viewDidLoadcan be called multiple times without deallocbeing called. This would then add the same observer multiple times, causing the handler to be called multiple times.

纵观各个苹果实例(例如添加音乐),其中我看到他们增加观察员默认NSNotificationCenterviewDidLoad,然后删除它们dealloc。这看起来很危险,因为viewDidLoad可以多次dealloc调用而不被调用。这将多次添加相同的观察者,导致多次调用处理程序。

A solution to this would be to also remove observers in viewDidUnload, but this would then mean the same observer could be removed for a second time in deallocwhich seems like a potential problem.

对此的解决方案是同时移除 中的观察者viewDidUnload,但这意味着可以再次移除同一个观察者,dealloc这似乎是一个潜在的问题。

What am I missing?

我错过了什么?

回答by Lorenzo B

There are a lot of discussions about removing notifications in the right way. For example:

有很多关于以正确的方式删除通知的讨论。例如:

I suggest you to remove observers in viewWillDisappear(or viewDidDisappear) and viewDidUnloadlifecycle methods. (Note:viewDidUnloadwas deprecated and shouldn't be implemented in iOS6+; see iOS 6 - viewDidUnload migrate to didReceiveMemoryWarning?)

我建议您删除viewWillDisappear(or viewDidDisappear) 和viewDidUnload生命周期方法中的观察者。(注意:viewDidUnload已弃用,不应在 iOS6+ 中实现;请参阅iOS 6 - viewDidUnload 迁移到 didReceiveMemoryWarning?

An important note:

一个重要的注意事项:

viewDidUnloadis not guaranteed to be called - it's not a standard lifecycle method.

viewDidUnload不能保证被调用 - 它不是标准的生命周期方法。

From Apple doc:

来自苹果文档:

viewDidUnload When a low-memory condition occurs and the current view controller's views are not needed, the system may opt to remove those views from memory. This method is called after the view controller's view has been released and is your chance to perform any final cleanup.

viewDidUnload 当内存不足且不需要当前视图控制器的视图时,系统可能会选择从内存中删除这些视图。这个方法在视图控制器的视图被释放后被调用,这是您执行任何最终清理的机会。

Instead, deallocis called whenever the number of references for that receiver is zero.

相反,dealloc只要该接收器的引用数为零,就会调用它。

Hope it helps.

希望能帮助到你。

Edit

编辑

For the sake of completeness you can see this link on how to avoid-nsnotification-removeobserver. The link provide some useful guidelines to remove observer (see also the comments). The author does it in viewDidAppear/viewDidDisappearmethods since viewWillAppearand viewWillDisappearare not always called correctly in many applications. It's your choice.

为了完整起见,您可以查看有关如何避免-nsnotification-removeobserver 的链接。该链接提供了一些有用的指南来删除观察者(另见评论)。笔者做它viewDidAppear/viewDidDisappear因为方法viewWillAppearviewWillDisappear并不总是在许多应用中正确调用。这是你的选择。

If you want to be sure to remove observers in the right way unregister it in deallocmethod or when the view is fully unloaded as you wrote in the second comment. But be sure that deallocwill be call in the future. In other words, as I already mentioned, if the controller continues to stay alive since some other object has a referenced to it, the method will never get called. In this case the controller continues to receive notifications.

如果您想确保以正确的方式删除观察者,请在方法中取消注册,dealloc或者当您在第二条评论中写道时完全卸载视图。但请确保dealloc将来会调用。换句话说,正如我已经提到的,如果控制器继续保持活动状态,因为某个其他对象引用了它,则该方法将永远不会被调用。在这种情况下,控制器会继续接收通知。

回答by Darshit Shah

- (void)viewWillAppear:(BOOL)animated
{
   [super viewWillAppear:animated];
   [[NSNotificationCenter defaultCenter] addObserver:self .........]
}

- (void)viewWillDisappear:(BOOL)animated
{
   [super viewWillDisappear:animated];
   [[NSNotificationCenter defaultCenter] removeObserver:self .........];
}

回答by Cem Schemel

For folks stumbling on this page more recently, the removal of observers might not be necessary anymore. The "Discussion" section of the addObserver(_:selector:name:object:)docssay:

对于最近在此页面上绊倒的人们,可能不再需要移除观察者。文档“讨论”部分addObserver(_:selector:name:object:)说:

If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its deallocmethod. Otherwise, you should call removeObserver(_:name:object:)before observer or any object passed to this method is deallocated.

如果您的应用面向 iOS 9.0 及更高版本或 macOS 10.11 及更高版本,则无需在其dealloc方法中取消注册观察者。否则,您应该removeObserver(_:name:object:)在观察者或传递给此方法的任何对象被释放之前调用。

回答by mprivat

Why would you not do it in viewWillAppear/ viewDidDisappear? You only care about the notifications when your view is showing anyway, right?

你为什么不在viewWillAppear/ 中做呢viewDidDisappear?无论如何,您只关心视图显示时的通知,对吗?

回答by Sola Zhou

You can addObserver in viewWillAppear,and removeObserver in viewWillDisappear. but viewWillAppear may called many times. so you can remove Notification first then addObserver.

您可以在viewWillAppear 中添加Observer,在viewWillDisappear 中移除Observer。但viewWillAppear中可以调用多次。所以你可以先删除通知,然后添加观察者。

 -(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:YES];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)name:@"UIKeyboardWillShowNotification"object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)name:@"UIKeyboardWillHideNotification"object:nil];
 }

 -(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:YES];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillShowNotification" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"UIKeyboardWillHideNotification" object:nil];
 }