【问题标题】:NSNotification is being called multiple times from UITabBarController从 UITabBarController 多次调用 NSNotification
【发布时间】:2014-01-09 19:33:55
【问题描述】:

我有一个UITabBarController,它有 4 个标签。这些选项卡中的每一个都是一个单独的UIViewController。我在这 4 个 VC 中的每一个上都有对象,它们使用 NSNotification 在按下某个对象时执行操作。 4 个 VC 都以相同的方式响应通知,因为它是每个页面上的类似对象。当这个对象被按下时,它会在当前视图控制器上呈现一个视图。问题是,如果我现在移动到其他 3 个选项卡中的任何一个,该视图也在他们的 VC 上。这是因为当在任何 VC 上按下通知时,所有 4 个选项卡上都会响应通知。我需要它只响应用户当前使用的 VC,而不是标签栏中的任何其他 VC。

有没有办法让它正常工作?也许是一个阈值,您可以在其中设置通知在被调用后可以执行其选择器的次数?这样我可以将其设置为 1,并且在任何给定时间,如果调用该通知,则只能调用选择器 1 次。

我使用的对象实现类型要求我使用NSNotification,因此无法更改我的交互方式。

编辑:

这个viewDidLoad 方法在我的标签栏中的 4 个 VC 的顶层 VC 上。他们四个要么直接使用它,要么继承自它。

- (void) viewDidLoad
{
    ...
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didSelectItemFromCollectionView:) name:@"didSelectItemFromCollectionView" object:nil];
}

动作处理器:

- (void) didSelectItemFromCollectionView:(NSNotification *)notification
{
    NSDictionary *cellData = [notification object];

    if (cellData)
    {
        NewVC *pushToVC = [self.storyboard instantiateViewControllerWithIdentifier:@"PushToVC"];

        [self.navigationController pushViewController:pushToVC animated:YES];
    }
}

4 个 VC 中的每一个都是一个UITableViewController,并且具有带有可以按下对象的单元格。这个NSNotificationCenter 操作是允许操作工作的原因。

【问题讨论】:

  • 您能给我们一些代码以便我们提供帮助吗?

标签: ios objective-c uitabbarcontroller nsnotificationcenter


【解决方案1】:

你必须在每个viewController-viewDidLoad中实现NSNotificationCenter-addObserver:selector:name:object:方法

示例:

- (void)viewDidLoad
{
    //...
    [NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(doSomething:) 
                                                name:@"TestNotification"
                                              object:nil];
}

不要在-viewDidLoad 中使用它,而是在-viewWillAppear 中移动它并在-viewWillDisappear 中实现removeObserver:name:object:

这样,只有当前开启viewController会响应通知。

示例:

- (void)viewWillAppear:(BOOL)animated
{
    //...
    [NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(doSomething:) 
                                                name:@"TestNotification"
                                              object:nil];
}

- (void)viewWillDisappear:(BOOL)animated
{
    //...
    [NSNotificationCenter defaultCenter] removeObserver:self
                                                   name:@"TestNotification"
                                                 object:nil];
}

- (void)doSomething:(NSNotification *)userInfo
{
    //...
    //if you push a viewController then the following is all you need
    [self.navigationController pushViewController:vcSomething
                                         animated:YES];

    //however.... if you're instead presenting a viewController modally then
    //you should implement "-removeObserver:name:object: in this method as well

    //[NSNotificationCenter defaultCenter] removeObserver:self
    //                                               name:@"TestNotification"
    //                                             object:nil];
    //[self presentViewController:vcSomething
    //                   animated:YES
    //                 completion:nil];

    //OR... in the completion parameter as:

    //[self presentViewController:vcSomething
    //                   animated:YES
    //                 completion:^{
    //                     [NSNotificationCenter defaultCenter] removeObserver:self
    //                                                                    name:@"TestNotification"
    //                                                                  object:nil];
    //                 }];
}

编辑:

您 (@Jonathan) 评论道:

非常感谢您的回答,这对我帮助很大!一世 实际上遇到了另一个发生此问题的情况,我是 不知道如何弄清楚。现在我有一个 VC 介绍 另一个VC模态。每个人都有相同的观察者 NS通知。当我在 以模态方式呈现 VC,但一旦我关闭该 VC 并返回 底层我在通知的地方有同样的问题 多次调用。您对此有解决方案的想法吗 案例?

现在...关于这个...

首先...注意:

  1. 多个-addObserver:selector:name:object: 将多次注册指定的通知(意味着...相同的通知被注册 N 次将调用调用目标选择器 N 次
  2. Parent viewController 提供 ViewController(称为 Child)将调用 Parent 的 -viewWillDisappear:
    在哪里...
  3. 解雇 Child viewController 仍会调用 Parent-viewWillAppear:

这会造成逻辑上的不平衡,如果不加以处理(根据上面 doSomething 方法的代码示例中的注释行),它会导致 Parent 注册通知倍数次(因为它的 -viewWillAppear: 方法经常被调用 -viewWillDisappear:

另见:similar question

【讨论】:

  • 这是为我做的!在 viewWillAppear/Disappear 中添加/删除观察者。我之前在 viewDidLoad 方法中添加了观察者,并在 Dealloc 方法中删除了它们。这是否意味着我应该删除 dealloc 方法并将其留给 viewWillDisappear 来删除观察者?非常感谢您的帮助!
  • @Jonathan :在您的情况下,应该按照答案,而在一般情况下,请参阅this link。长话短说......如果你没有在任何地方为班级做-removeObserver:,那么可以,在dealloc方法中调用它,或者......在-viewWillDisappear:中调用它。你的愿望
  • 非常感谢您的回答,这对我帮助很大!实际上,我遇到了另一个发生此问题的情况,我不确定如何解决。现在我有一个 VC,它以模态方式呈现另一个 VC。每个人都有相同的 NSNotification 的观察者。当我在模态呈现的 VC 中时,一切都表现得非常好,但是一旦我关闭了该 VC 并返回到底层,我就会遇到同样的问题,即多次调用通知。在这种情况下,您有解决方案的想法吗?
  • @Jonathan :当您呈现viewController(例如,孩子)时,父母-viewController-viewWillDisappear: 不会被调用,但是,当您解雇孩子viewController , 父母的viewWillAppear: 被调用,最终你的父母有多个-addObserver:(而不是-removeObserver:),这意味着,它将响应通知的次数等于addObserver 在同一通知上的次数完毕。为此,现在,我能想到的就是在你呈现孩子的方法中做-removeObserver 甚至
  • @Jonathan :好的,废话,我会更新这个答案
【解决方案2】:

它应该只被调用一次,这样它就不会被再次调用

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(methodName:) name:@"name" object:nil];
});

【讨论】:

    猜你喜欢
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多