NSNotificationCenter removeObserver:name:object:不删除观察者

时间:2014-04-24 12:16:58

标签: objective-c nsnotificationcenter nsnotifications

我在视图控制器中有一个设置一些通知的方法:

- (void)processState
{
    MYGame *game = [[MYGameManager sharedInstance] getGameAtIndex:self.indexPath.row];

    if(game)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notification_gameUpdated:) name:kMYNotificationGameUpdated object:game];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notification_gameEnded:) name:kMYNotificationGameEnded object:game];
    }
}

然后有一个游戏更新方法,每隔一段时间调用一次:

- (void)notification_gameUpdated:(NSNotification *)notification
{
    MYGame *game = notification.object;
    _game_status = (game.entity.bet.isWinning) ? MYGameStatusWin : MYGameStatusLose;
}

最后,当比赛结束时:

- (void)notification_gameEnded:(NSNotification *)notification
{
    MYGame *game = notification.object;

    // Clear the notifications   
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kMYNotificationGameUpdated object:game];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:kMYNotificationGameEnded object:game];

    self.gameIsActive = NO;
}

麻烦的是,即使我删除观察者(并且断点显示正在发生这种情况),那么notification_gameUpdated:方法仍然被调用。如果我将其更改为

[[NSNotificationCenter defaultCenter] removeObserver:self name:kMYNotificationGameUpdated object:nil];

这仍然不清楚。但如果我把它改成

[[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:game];

然后 清除它。

[[NSNotificationCenter defaultCenter] removeObserver:self];

但是我并不热衷于这样做,因为我觉得代码很干净而且我不想要任何"陷阱"如果我需要添加更多的观察者,那就更进一步了。我已经检查了其余的代码,并且找不到任何其他类将观察者添加到此对象,尽管其他视图控制器会侦听相同的消息。

3 个答案:

答案 0 :(得分:3)

processState被调用多次?这可以解释你所看到的行为。

如果是,解决问题的一种方法是在添加侦听器之前始终删除侦听器。参见例如this answer

答案 1 :(得分:1)

编辑#2

尝试注册object:nil,当您发布通知时,请在game字典中包含对userInfo的引用。然后,在接收器中,您可以与game进行比较,并执行您想要的任何操作(如果匹配)。这应该会让您获得与使用object:game时相同的行为,尽管它无法解释您当前实施的原因是什么


当您注册这样的通知时:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(notification_gameUpdated:)
                                             name:kMYNotificationGameUpdated 
                                           object:game];

@selector仅在game的特定实例是发件人时才会执行。 您是否有可能在注册后重新初始化game的共享实例?这可能会导致您遇到的行为

尝试使用object:nil注册通知,看看会发生什么。 (假设没有多个游戏并发运行)

答案 2 :(得分:0)

事实证明,问题的原因是Method Swizzling。我正在处理的项目已addObserver:selector:name:object:removeObserver:name:object:进行了调整。问题是虽然addObserver已正确处理,但removeObserver仅在特定条件下删除对象。这显然需要改变......

但是我发布这个作为对他人的警告......嗖嗖声对你的健康有害!

任何时候的道歉都浪费了。