【问题标题】:What's the better way to addObserver/removeObserver with NSNotificationCenter?使用 NSNotificationCenter 添加Observer/removeObserver 的更好方法是什么?
【发布时间】:2012-05-17 07:09:31
【问题描述】:

我曾经在viewDidLoad: 中使用addObserver,在dealloc: 中使用removeObserver。代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(refreshData)
                                                 name:AnyNotification
                                               object:nil];
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:AnyNotification
                                                  object:nil];
}

但是根据一些文章所说,最好在viewDidAppear:addObserverremoveObserverviewDidDisappear: 中。代码:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(refreshData)
                                                 name:AnyNotification
                                               object:nil];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:AnyNotification
                                                  object:nil];
}

那么,添加Observer/removeObserver 的更好方法是什么?

【问题讨论】:

  • dealloc中删除观察者是不好的,以防可能发生内存警告。
  • 视图确实消失了,只要确保删除每个特定通知的观察者,而不是 removeObserver:self,否则当视图重新出现时,您会删除超类通知观察者。

标签: iphone objective-c cocoa-touch


【解决方案1】:

这取决于您的情况,通常最好的方法是添加 viewDidLoad 并删除 deallocviewDidUnload(在 iOS 9.0 中已弃用,仅使用 dealloc),但在某些情况下您在不同的类(如 UI 效果)中具有相同的方法,并且只想使用通知调用当前屏幕的方法,那么您必须在 viewWillAppear 中添加观察者并在 viewWillDisappearviewDidAppear/viewDidDisappear 中删除它

编辑: cmets 的说明,谢谢@honey。

虽然现在从 iOS 9 开始,您不再需要关心移除观察者。请参阅Apple release notes:“在 OS X 10.11 和 iOS 9.0 中,NSNotificationCenter 和 NSDistributedNotificationCenter 将不再向可能被释放的已注册观察者发送通知..

【讨论】:

  • 我认为第一个解决方案不是最好的,因为可能存在类已初始化但视图未加载的情况。应用程序将崩溃并出现错误“无法从 中删除密钥路径“KEY_PATH”的观察者 ,因为它没有注册为观察者。”
  • @DanSkeel 可以添加 initawakeFormNib?
  • 为什么最好添加viewDidLoad,而不是viewWillAppear?我没有看到好处。我更喜欢只在需要时让观察者留在身边,所以我使用viewWillAppearviewWillDisappear。此外,这些调用似乎是可靠配对的。
  • 好吧,如果您需要在堆栈中的当前视图控制器之前更新 rootviewcontroller 或任何视图控制器中的某个日期,如果您使用 viewWillAppear/Disappear,您的通知将不会触发到前一个视图控制器。如问题中所述,这取决于场景
  • @DanSkeel 如果您有这种可能的情况,那么这可能意味着viewDidLoad 不是您应该写观察者的地方。每个业务/UI 需求都应该有自己适当的周期。虽然现在从 iOS 9 开始,您不再需要关心删除观察者。请参阅Apple release notes:“在 OS X 10.11 和 iOS 9.0 中,NSNotificationCenter 和 NSDistributedNotificationCenter 将不再向可能被释放的已注册观察者发送通知......”
【解决方案2】:

我通常会将其放在-viewDidAppear:-viewDidDisapear:(或-viewWillAppear:-viewWillDisappear:)中,因为在每种情况下,我只对实际显示视图的通知感兴趣。

这可能是一个过早的优化(处理通知的代码可能需要一些时间,但如果视图未显示,则可能无用),但它也不再是代码 - 它是相同的代码,只是方法不同。 ..

【讨论】:

  • 这是正确的方法,因为有时可以加载视图但不会立即出现在屏幕上,例如在实现 UIStateRestoring 时。如果 viewWillAppear 中的 isMovingToParentViewController 只做一次,你可以使用它。
【解决方案3】:

不要忘记 NSKeyValueObservingOptionInitial。我将它与 viewWillAppear/viewWillDisappear 一起使用,因此我的 UI 始终是最新的,即使我隐藏了该视图控制器,节省资源,因为在再次显示之前我不会更新它。

【讨论】:

    【解决方案4】:

    使用 NSNotifications 的最佳方法是在需要观察通知时添加观察者在不再需要时删除它们

    这可能发生在viewDidLoad:viewWillAppear:,或者当用户点击某个按钮等时。

    我给你举个小例子:

    我的应用程序有一个标签栏,在一些视图控制器中,我显示了一些从互联网下载的信息(例如一条推文)。我还有一个类池,每 2 分钟从服务器收集新数据,并且由于服务器有新数据,我更新了数据库信息。我不会使用委托模式来监听 DB 更改,因为我有很多视图控制器显示数据,将委托作为一个数组并循环为每个视图控制器传递数据将是一个非常糟糕的设计。因此,在这种特定情况下,最好的办法是发布通知,告诉每个 VC 新数据已经到来。

    如果您的 VC 在视图消失时删除了委托,则只有当前的委托会收到通知并更新显示内容。

    您显然可以在显示之前更新其他 VC 的内容,例如 viewWillAppear:,但这样做不仅会在必要时更新 VC 内容,而且每次更改选项卡时都会更新。

    这只是一个示例,我试图向您展示对于 NSNotifications,当我们没有关于您的应用行为方式的完整描述时,很难建议您何时添加或删除观察者。

    【讨论】:

      【解决方案5】:

      -viewWillAppear: + -viewWillDisappear: 优于 -viewDidAppear: + -viewDidDisapear:,因为它们的调用次数总是相同。

      【讨论】:

      • @ToolmakerSteve,他们是配对的。
      • @ToolmakerSteve ,当导航控制器的 interactivePopGestureRecognizer 启用时。
      • 好的,我明白你现在在说什么了。我已经编辑了你的措辞以使其更清晰,并支持你,因为我相信你提出了一个重要的观点。 [虽然我目前没有开发应用程序,所以我无法确认Did 功能并不总是平衡的。](其他人一定对你投了反对票,也许出于同样的原因我很困惑 - 说不出来你在说什么。)
      • @ToolmakerSteve,(o^^o)我知道。但由于我的英文写作不好,我无法准确表达。
      猜你喜欢
      • 1970-01-01
      • 2014-11-11
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 2011-10-30
      • 2023-04-02
      • 2014-05-03
      • 2014-03-27
      相关资源
      最近更新 更多