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

时间:2012-04-26 12:13:15

标签: objective-c ios dealloc nsnotificationcenter addobserver

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

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

我错过了什么?

5 个答案:

答案 0 :(得分:24)

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

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

重要提示:

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

来自Apple doc:

  

viewDidUnload   当发生低内存条件和当前视图控制器时   如果不需要视图,系统可能会选择从中删除这些视图   记忆。在视图控制器的视图之后调用此方法   已经发布,你有机会进行任何最后的清理工作。

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

希望它有所帮助。

修改

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

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

答案 1 :(得分:2)

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

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

答案 2 :(得分:2)

对于最近在这个页面上磕磕绊绊的人来说,可能不再需要删除观察员了。 "Discussion" section of the addObserver(_:selector:name:object:) docs说:

  

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

答案 3 :(得分:1)

为什么不在viewWillAppear / viewDidDisappear中执行此操作?您只关注视图显示时的通知,对吗?

答案 4 :(得分:0)

您可以在viewWillAppear中添加addserver,并在viewWillDisappear中删除removeObserver。 但是viewWillAppear可能会多次调用。所以你可以先删除Notification,然后再删除addObserver。

 -(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];
 }