我有一个客观的C类。在其中,我创建了一个init方法并在其中设置了NSNotification
//Set up NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(getData)
name:@"Answer Submitted"
object:nil];
我在哪个地方设置[[NSNotificationCenter defaultCenter] removeObserver:self]
?我知道对于UIViewController
,我可以将其添加到viewDidUnload
方法中如果我刚刚创建了一个目标c类,需要做什么?
答案 0 :(得分:111)
通用答案将是“一旦您不再需要通知”。这显然不是一个令人满意的答案。
我建议您在这些类的方法[notificationCenter removeObserver: self]
中添加一个调用dealloc
,您打算将其用作观察者,因为这是彻底取消注册观察者的最后机会。但是,这只会保护您免受由于通知中心通知死对象而导致的崩溃。当您的对象尚未/不再处于可以正确处理通知的状态时,它无法保护您的代码免受接收通知。为此...见上文。
编辑(因为答案似乎吸引了比我想象的更多的评论)所有我想在这里说的是:很难就什么时候最好删除来自通知中心的观察员,因为这取决于:
所以,我可以提出最好的一般建议:保护你的应用程序。至少在一次可能的失败中,removeObserver:
在dealloc
跳舞,因为那是最后一点(在对象的生命中),你可以干净利落地做到这一点。这并不意味着:“只要推迟删除,直到调用dealloc
,一切都会好的”。相反,只要对象不再准备好(或需要)接收通知,就立即删除观察者。那是恰到好处的时刻。不幸的是,不知道上面提到的任何问题的答案,我甚至无法猜测,那个时刻会是什么时候。
您可以多次安全removeObserver:
一个对象(除了与给定观察者的第一次调用之外的所有对象都是nops)。所以:考虑在dealloc
中再次这样做(只是为了确定),但首要的是:在适当的时候(由你的用例决定)。
答案 1 :(得分:38)
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)
}
}
override func viewWillDisappear(animated: Bool){
super.viewWillDisappear(animated)
if self.isBeingDismissed() //presented view controller
{
// remove observer here
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
在 iOS 6.0 > version
中,最好将 viewWillDisappear
中的观察者移除为 viewDidUnload
方法弃用。
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
从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];
}
}
- (void)viewWillDisappear:(BOOL)animated{
if ([self isBeingDismissed] == YES) ///presented view controller
{
// remove observer here
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
}
}
答案 2 :(得分:37)
从iOS 9开始,不再需要移除观察者。
在OS X 10.11和iOS 9.0 NSNotificationCenter和 NSDistributedNotificationCenter将不再向其发送通知 可能被解除分配的注册观察员。
答案 3 :(得分:25)
如果将观察者添加到视图控制器,我强烈建议您将其添加到viewWillAppear
并在viewWillDisappear
中将其删除。
答案 4 :(得分:18)
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
答案 5 :(得分:8)
一般情况下,我将其放入dealloc
方法。
答案 6 :(得分:7)
快速使用deinit因为dealloc不可用:
deinit {
...
}
Swift文档:
在类实例之前立即调用deinitializer 释放。您使用deinit关键字编写deinitializers,类似 如何使用init关键字编写初始化器。 Deinitializers 仅适用于班级类型。
通常,您不需要执行手动清理 实例被解除分配。但是,当您使用自己的时 资源,您可能需要执行一些额外的清理 你自己。例如,如果您创建一个自定义类来打开文件和 向它写一些数据,你可能需要先关闭文件 类实例被解除分配。
答案 7 :(得分:5)
*编辑:此建议适用于iOS< = 5(即使您应该添加viewWillAppear
并删除viewWillDisappear
- 但是如果由于某种原因您添加了观察者在viewDidLoad
)
如果您已在viewDidLoad
中添加了观察者,则应在dealloc
和viewDidUnload
中将其删除。否则,在viewDidLoad
之后调用viewDidUnload
时,最终会将其添加两次(这将在内存警告之后发生)。这在iOS 6中不是必需的,其中viewDidUnload
已被弃用且不会被调用(因为视图不再自动卸载)。
答案 8 :(得分:5)
在我看来,以下代码在 ARC 中是没有意义的:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
在 iOS 6 中,删除viewDidUnload
中的观察者也没有意义,因为它现在已被弃用。
总而言之,我总是在viewDidDisappear
中这样做。但是,这也取决于你的要求,就像@Dirk说的那样。
答案 9 :(得分:4)
我想我找到了一个可靠答案!我必须这样做,因为上面的答案含糊不清,看起来很矛盾。我浏览了Cookbook和Programming Guides。
首先,addObserver:
中的viewWillAppear:
和removeObserver:
中的viewWillDisappear:
的样式对我不起作用(我测试了它),因为我在儿童中发布通知查看控制器以在父视图控制器中执行代码。如果我在同一个视图控制器中发布和监听通知,我只会使用这种风格。
我将最依赖的答案,我在iOS编程中发现:Big Nerd Ranch Guide 4th。我相信BNR的人,因为他们有iOS培训中心,他们不只是写另一本食谱。准确可能符合他们的最佳利益。
BNR示例一:addObserver:
中的init:
,removeObserver:
中的dealloc:
BNR示例二:addObserver:
中的awakeFromNib:
,removeObserver:
中的dealloc:
...在dealloc:
移除观察者时,他们不使用[super dealloc];
我希望这有助于下一个人...
我正在更新这篇文章,因为Apple现在几乎完全没有使用Storyboard,所以上面提到的可能并不适用于所有情况。重要的是(以及我首先添加这篇文章的原因)是要注意你的viewWillDisappear:
是否被调用。当应用程序进入后台时,它不适合我。
答案 10 :(得分:2)
接受的答案不安全,可能导致内存泄漏。请将取消注册保留在dealloc中,但也要在viewWillDisappear中取消注册(当然,如果您在viewWillAppear中注册)....这就是我所知道的并且它工作得很好! :)
答案 11 :(得分:1)
重要的是还要注意,当视图控制器呈现新的UIView时,也会调用viewWillDisappear
。该委托只是表明视图控制器主视图在显示屏上不可见。
在这种情况下,如果我们使用通知允许UIview与父视图控制器通信,则在viewWillDisappear
中取消分配通知可能会很不方便。
作为一种解决方案,我通常会在以下两种方法中删除观察者:
- (void)viewWillDisappear:(BOOL)animated {
NSLog(@"viewController will disappear");
if ([self isBeingDismissed]) {
NSLog(@"viewController is being dismissed");
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
}
}
-(void)dealloc {
NSLog(@"viewController is being deallocated");
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
}
出于类似的原因,当我第一次发出通知时,我需要考虑这样一个事实,即任何时候出现在控制器上方的视图然后viewWillAppear
方法被触发。这将反过来生成相同通知的多个副本。由于无法检查通知是否已处于活动状态,因此我会在添加通知之前删除通知来解决问题:
- (void)viewWillAppear:(BOOL)animated {
NSLog(@"viewController will appear");
// Add observers
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"imageGenerated" object:nil]; // This is added to avoid duplicate notifications when the view is presented again
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedImageFromCameraOrPhotolibraryMethodOnListener:) name:@"actionCompleted" object:nil];
}
答案 12 :(得分:0)
SWIFT 3
有两种使用通知的情况: - 只有当视图控制器在屏幕上时才需要它们; - 即使用户在当前打开另一个屏幕,也总是需要它们。
对于第一种情况,添加和删除观察者的正确位置是:
/// Add observers
///
/// - Parameter animated: the animation flag
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(...)
}
/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
对于第二种情况,正确的方法是:
/// Add observers
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(...)
}
/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed // remove only when view controller is removed disappear forever
|| !(self.navigationController?.viewControllers.contains(self) ?? true) {
NotificationCenter.default.removeObserver(self)
}
}
永远不会将removeObserver
放入deinit{ ... }
- 这是一个错误!
答案 13 :(得分:0)
override func viewDidLoad() { //add observer
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector:#selector(Yourclassname.method), name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}
override func viewWillDisappear(_ animated: Bool) { //remove observer
super.viewWillDisappear(true)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}