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

发布于 2024-12-09 20:48:16 字数 402 浏览 5 评论 0原文

我有一个 NSNotification 观察者,它被调用了两次。我不知道该怎么办。

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

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

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

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

I have an observer of NSNotification which is called twice. I do not know what to do with it.

I googled it but no solution found.

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

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

沙与沫 2024-12-16 20:48:16

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

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

[[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];

Solution 1: The first thing is to check if the notification itself is posted twice.

Solution 2: Even if the notification is posted only once, the action will be called as many times you've added the observer for the notification (no matter the notification is same or not). For example, the following two lines will register the observer(self) for the same notification(aSelector) twice.

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

You have to find where you are adding observer for the second time, and remove it. And also make sure that the code where you are add the observer is not called twice.

Solution 3: If you are not sure whether you have already added the observer or not, you can simply do the following. This will make sure that the observer is added only once.

[[NSNotificationCenter defaultCenter] removeObserver:self name:aName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil];
|煩躁 2024-12-16 20:48:16

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

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

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

If your addObserver method is run multiple times, it will create multiple observers. My issue was that I somehow placed my observer in viewWillAppear which appeared multiple times before I posted the notification and it resulted in my observer being called multiple times.

While EmptyStack's 3rd solution works, there is a reason your observer is being called twice, so by finding it, you can prevent needless lines of code instead of removing and adding the same observer.

I would suggest putting your observer in viewDidLoad to avoid simple errors like the one I experienced.

逐鹿 2024-12-16 20:48:16

尝试在 viewWillDisappear 方法中删除Observer:

-(void)viewWillDisappear:(BOOL)animated{

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

Try to removeObserver in viewWillDisappear method :

-(void)viewWillDisappear:(BOOL)animated{

[[NSNotificationCenter defaultCenter] removeObserver:self name:@"startAnimating" object:nil]; }
热情消退 2024-12-16 20:48:16

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

Try set a breakpoint on [[NSNotificationCenter defaultCenter] addObserver:self selector:aSelector name:aName object:nil]; and check if it is called more than once.

许你一世情深 2024-12-16 20:48:16

对于那些在 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)

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

For those looking for a solution in Swift 2.2 and above and who have reached this question like me you can create an extension as follows :

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)
  }
}

You can call this method as follows :

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

The extension will handle the removal of previous observer if it exists. Even if there was no previous observer present this code won't crash.

烟雨凡馨 2024-12-16 20:48:16

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

I had two instances of the same class and it took me some time before I have realised that the notification is not running twice in one instance of that class but twice in two instances.

颜漓半夏 2024-12-16 20:48:16

我在基于文档的应用程序中使用通知。每个文档的观察者类(ViewController)都会捕获该通知。打开两个文档,函数被调用两次。打开三个文档...您就明白了。

为了限制谁接收通知,您可以指定您对特定对象感兴趣,但这有一个问题:该对象必须是类对象的同一实例;你不能简单地比较一个值;所以 UUID 不匹配,但实例

class DocumentID {
    var id = UUID()
}

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

I use notifications in a document-based app. Every document's observer class (a ViewController) caught the notification. Two documents open, function was called twice. Three documents open... you get the drift.

To limit who receives the notification, you can specify that you're interested in a particular object, but this has a twist: the object needs to be the same instance of a class object; you cannot simply compare a value; so UUID does not get matched, but an instance of

class DocumentID {
    var id = UUID()
}

works fine. Inject this from your Document to every class that sends or receives notifications, and you've limited notifications to your document.

极致的悲 2024-12-16 20:48:16

Swift 5+ 解决方案

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

几个提示(几个总是意味着 2):

  1. 选择器方法必须暴露给 @objc 才能工作,因此根据我们的示例:

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

    <前><代码>init() {
    NotificationCenter.default.addObserver(self, 选择器: #selector(aSelector), 名称: aName, 对象: nil)
    //在这里添加任何其他通知
    }

    去初始化(){
    NotificationCenter.default.removeObserver(self)
    }

Swift 5+ Solution

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

A couple of tips (and a couple ALWAYS means 2):

  1. Selector method must be exposed to @objc to work, so per our example:

    @objc func aSelector() { //do work here }
    
  1. I put the notifications in the init() and deinit() and use singletons to avoid repeating them, like this:

    init() {
        NotificationCenter.default.addObserver(self, selector: #selector(aSelector), name: aName, object: nil)
        //add any other notifications here
    }
    
    deinit() {
        NotificationCenter.default.removeObserver(self)
    }
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文