19

查看各种 Apple 示例(例如Add Music),在这些示例中,我看到他们将观察者添加到默认值NSNotificationCenterviewDidLoad然后将它们删除dealloc。这似乎很危险,因为viewDidLoad可以多次调用而不dealloc被调用。然后这将多次添加相同的观察者,导致处理程序被多次调用。

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

我错过了什么?

4

5 回答 5

25

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

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

重要说明:

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

来自苹果文档:

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

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

希望能帮助到你。

编辑

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

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

于 2012-04-26T13:45:50.190 回答
2
- (void)viewWillAppear:(BOOL)animated
{
   [super viewWillAppear:animated];
   [[NSNotificationCenter defaultCenter] addObserver:self .........]
}

- (void)viewWillDisappear:(BOOL)animated
{
   [super viewWillDisappear:animated];
   [[NSNotificationCenter defaultCenter] removeObserver:self .........];
}
于 2013-12-23T07:19:45.687 回答
2

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

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

于 2018-02-06T04:33:12.107 回答
1

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

于 2012-04-26T13:25:13.147 回答
0

您可以在 viewWillAppear 中添加观察者,并在 viewWillDisappear 中删除观察者。但是 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];
 }
于 2015-09-16T02:44:23.317 回答