【问题标题】:Adding and removing observers to NSNotificationCenter in a UIViewController在 UIViewController 中向 NSNotificationCenter 添加和删除观察者
【发布时间】:2012-04-26 12:13:15
【问题描述】:

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

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

我错过了什么?

【问题讨论】:

  • 我不认为移除一个不存在的观察者有任何不利影响。
  • @jbat100 谢谢。我绝对认为删除 dealloc 和 viewDidUnload 中的观察者是唯一的方法。

标签: objective-c ios dealloc nsnotificationcenter addobserver


【解决方案1】:

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

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

重要提示:

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

来自苹果文档:

viewDidUnload 当内存不足的情况发生并且当前视图控制器的 不需要视图,系统可能会选择从 记忆。这个方法在视图控制器的视图有之后被调用 已发布,您有机会执行任何最终清理工作。

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

希望对你有帮助。

编辑

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

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

【讨论】:

  • 谢谢。但正如你提到的; 'viewDidUnload 在 dealloc 方法之前没有被调用。有时会在没有调用 viewDidUnload 的情况下调用 VC 的 dealloc,在这种情况下,使用您的建议意味着 VC 在被释放后将作为观察者保留,因为永远不会调用 viewWillDisappear / viewDidunload。还是绝对保证在dealloc之前调用viewWillDisappear?
  • @1ndivisible viewWillDisappear 在视图从屏幕上消失之前被调用。这意味着当您从屏幕上移除视图的控制器时(例如,控制器从导航控制器中弹出),该方法被调用。我为你添加了一个编辑。
  • 不错。避免nsnotification-removeobserver 链接是一个不错的链接。不知道。
  • 无论您是否使用通知,您都应该确保调用dealloc!鉴于如果您的程序正常工作,那么它肯定会在对象被释放时被调用,dealloc 是注销的最佳位置,这使得init(或其变体)成为唯一的注册位置。跨度>
  • @mcmahon 是的,你是对的。我为此添加了一个编辑。感谢您的评论。
【解决方案2】:
- (void)viewWillAppear:(BOOL)animated
{
   [super viewWillAppear:animated];
   [[NSNotificationCenter defaultCenter] addObserver:self .........]
}

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 谢谢。我遇到了一个问题,即我的 viewWillDisappear 在没有 viewWillAppear 的情况下被调用,并且崩溃了。
    【解决方案4】:

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

    【讨论】:

    • 但据我所知,如果对象被解除分配,则无法保证调用 viewDidDisappear。如果不是,则对象在被释放后将作为观察者保留。
    • 显然他们总是会被调用。 (见上文)
    • 在某些应用程序中不关心视图何时不显示,即更新数据状态
    • 如果地址簿在应用程序处于后台时更新,或者即使我的应用程序处于另一个视图中,我仍然需要通知。因此 viewDidDisappear 不合适。
    • 不,我也关心被另一个视图覆盖的视图
    【解决方案5】:

    您可以在viewWillAppear 中添加Observer,在viewWillDisappear 中删除Observer。 但是 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];
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 2014-06-20
      • 1970-01-01
      • 2016-06-06
      • 1970-01-01
      相关资源
      最近更新 更多