如何阻止NSNotification中的Observer调用两次?

时间:2011-10-13 08:11:42

标签: iphone objective-c ios nsnotifications

我有NSNotification的观察者,被叫两次。我不知道该怎么做。

我用谷歌搜索但没有找到解决方案。

[[NSNotificationCenter defaultCenter] addObserver:self
     selector:@selector(connectedToServer:) name:@"ConnectedToServer" object:nil];

- (void)connectedToServer:(NSNotification*)notification {

    [[NSNotificationCenter defaultCenter] postNotificationName:@"SendMessageToServer" object:message];
}

9 个答案:

答案 0 :(得分:124)

解决方案1:首先要检查通知本身是否发布了两次。

解决方案2:即使通知仅发布一次,也会在您添加通知观察者的次数中调用操作(无论是通知是否相同)。例如,以下两行将为同一通知(self)注册观察者(aSelector)两次。

[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];

您必须找到第二次添加观察者的位置,然后将其删除。并且还要确保添加观察者的代码不会被调用两次。

解决方案3:如果您不确定是否已添加观察者,则只需执行以下操作即可。这将确保观察者只被添加一次。

[[NSNotificationCenter defaultCenter] removeObserver:self name:aName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];

答案 1 :(得分:15)

如果多次运行addObserver方法,它将创建多个观察者。我的问题是,我以某种方式将我的观察者放在viewWillAppear中,在我发布通知之前多次出现,导致我的观察者多次被调用。

虽然EmptyStack的第3个解决方案有效,但是你的观察者被调用两次是有原因的,所以通过找到它,你可以防止不必要的代码行,而不是删除和添加相同的观察者。

我建议将观察者放在viewDidLoad中,以避免像我经历过的那样简单的错误。

答案 2 :(得分:7)

尝试在viewWillDisappear方法中删除Observer:

-(void)viewWillDisappear:(BOOL)animated{

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"startAnimating" object:nil]; }

答案 3 :(得分:2)

尝试在[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];上设置一个断点,并检查它是否被多次调用。

答案 4 :(得分:2)

对于那些在Swift 2.2及以上版本中寻找解决方案并且像我一样已经达到此问题的人,您可以按如下方式创建扩展:

import Foundation

extension NSNotificationCenter {
  func setObserver(observer: AnyObject, selector: Selector, name: String?, object: AnyObject?) {
    NSNotificationCenter.defaultCenter().removeObserver(observer, name: name, object: object)
    NSNotificationCenter.defaultCenter().addObserver(observer, selector: selector, name: name, object: object)
  }
}

您可以按如下方式调用此方法:

NSNotificationCenter.defaultCenter().setObserver(self, selector: #selector(methodName), name: "name", object: nil)

扩展将处理先前观察者的删除(如果存在)。即使之前没有观察者存在,此代码也不会崩溃。

答案 5 :(得分:0)

我有两个相同类的实例,花了一些时间才意识到该通知不是在该类的一个实例中运行两次,而是在两个实例中运行两次。

答案 6 :(得分:0)

我在基于文档的应用程序中使用通知。每个文档的观察者类(一个ViewController)都捕获了该通知。打开两个文件,函数被调用了两次。打开了三个文档...您可以轻松解决问题。

要限制接收通知的人,可以指定您对特定对象感兴趣,但这有一个不同之处:该对象必须是类对象的同一实例;您不能简单地比较一个值;因此未匹配UUID,而是

的一个实例
class DocumentID {
    var id = UUID()
}

工作正常。将其从您的文档插入到发送或接收通知的每个类中,并且对文档的通知受到限制。

答案 7 :(得分:0)

Swift 5+ 解决方案

NotificationCenter.default.removeObserver(self, name: aName, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(aSelector), name: aName, object: nil)

一些提示(一些提示总是意味着 2):

  1. Selector 方法必须暴露给@objc 才能工作,所以按照我们的例子:

    @objc func aSelector() { //do work here }
    
  1. 我将通知放在 init()deinit() 中并使用单例来避免重复它们,如下所示:

    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(aSelector), name: aName, object: nil)
        //add any other notifications here
    }
    
    deinit() {
        NotificationCenter.default.removeObserver(self)
    }
    

答案 8 :(得分:0)

在我的情况下,Notification 正在调用 次数 我出现在同一屏幕上并导致触发 相同的操作 X numberofTime 我进入屏幕。因此,我删除了 Notification 中的 viewWillDisappear 观察者,这实际上是有效的,并且在同一屏幕中停止了多次触发的操作/方法。 >

感谢 Himanth 的回答,我已经想通了

  • Swift4
<块引用>

addObserver

 override func viewDidLoad(){
       super.viewDidLoad()

      NotificationCenter.default.addObserver(self, selector: #selector(self.yourNotificationAction(notification:)), name: Notification.Name("yourNotificationName"), object: nil)

}
<块引用>

removeObserver 屏幕消失时

 override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        NotificationCenter.default.removeObserver(self, name: Notification.Name("yourNotificationName"), object: nil)
      
    }