查看各种Apple示例(例如Add Music),其中我看到他们将观察者添加到NSNotificationCenter
中的默认viewDidLoad
,然后在dealloc
中删除它们。这似乎很危险,因为viewDidLoad
可以多次调用,而不会调用dealloc
。然后,这将多次添加相同的观察者,导致多次调用处理程序。
解决这个问题的方法是删除viewDidUnload
中的观察者,但这意味着可以在dealloc
中第二次移除相同的观察者,这似乎是一个潜在的问题。
我错过了什么?
答案 0 :(得分:24)
有很多关于以正确方式删除通知的讨论。例如:
我建议您删除viewWillDisappear
(或viewDidDisappear
)和viewDidUnload
生命周期方法中的观察者。 (注意: viewDidUnload
已被弃用,不应在iOS6 +中实施;请参阅iOS 6 - viewDidUnload migrate to didReceiveMemoryWarning?)
重要提示:
viewDidUnload
无法保证被调用 - 它不是标准的生命周期方法。
来自Apple doc:
viewDidUnload 当发生低内存条件和当前视图控制器时 如果不需要视图,系统可能会选择从中删除这些视图 记忆。在视图控制器的视图之后调用此方法 已经发布,你有机会进行任何最后的清理工作。
相反,只要该接收器的引用数为零,就会调用dealloc
。
希望它有所帮助。
修改强>
为了完整起见,您可以看到有关如何avoid-nsnotification-removeobserver的链接。该链接提供了一些有用的指导来删除观察者(另请参阅注释)。作者在viewDidAppear
/ viewDidDisappear
方法中执行此操作,因为viewWillAppear
和viewWillDisappear
并非总是在许多应用程序中正确调用。
这是你的选择。
如果您想确保以正确的方式删除观察者,请在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];
}