已发布对象观察到的NSNotification

时间:2011-12-31 05:58:22

标签: ios animation notifications objective-c-blocks nsnotificationcenter

请参阅下面的更新...虽然这最初似乎是一个动画问题,但事实证明这是一个通知问题。注意:即使被丢弃的对象也会观察NSNotification。请务必removeObserver:以避免这种情况。

我第一次使用基于块的动画,并遇到“完成”块似乎被多次调用一次“动画”块的情况。我无法理解为什么会发生这种情况,但是在我的游戏运行一段时间之后似乎发生了一些一致性。这是有问题的代码...

- (void)player:(Player *)player takeStep:(NSInteger)step onWalk:(NSArray *)walk {
    if (step < walk.count) {
        // take this step
        NSLog(@"taking step %i", step);
        NTTileView *tile = [walk objectAtIndex:step];
        [UIView animateWithDuration:0.5 animations:^{
            NSLog(@"animating step to tile %@",tile);
            [player.pawn moveToTile:tile];
            if ([[NSUserDefaults standardUserDefaults] boolForKey:@"UseAudio"]) [boombox play];
        } completion:^(BOOL finished){
            if (finished) {
                NSLog(@"step %i done, moving on",step);
                [self player:player takeStep:step+1 onWalk:walk];
            } else {
                NSLog(@"step %i unfinished, jumping to end",step);
                NTTileView *lastTile = [walk lastObject];
                [player.pawn setCenter:lastTile.center];
            }
        }];
    }
}

这是一个递归方法,最初使用step = 1启动,并使用一系列“tiles”为玩家的pawn设置动画。完成每个步骤后,递归调用该方法以进行下一步。当阵列用完图块时,作业就完成了。在完成的块中,我们要么采取下一步,要么(如果动画没有完成),只需跳到最后一个图块。这是一个贯穿......的日志。

1...[79719:1be03] taking step 1
2...[79719:1be03] animating step to tile <NTTileView: 0x957cd30; baseClass = UIControl; frame = (273 260; 57 54); layer = <CALayer: 0x957cc90>>; id = 31; type = TileTypeMethods; isHub = 0; isEndSpot = 0
3...[79719:1be03] step 1 done, moving on
4...[79719:1be03] taking step 2
5...[79719:1be03] animating step to tile <NTTileView: 0x957d3b0; baseClass = UIControl; frame = (268 202; 60 59); layer = <CALayer: 0x957d2e0>>; id = 30; type = TileTypeTermsAndTheory; isHub = 0; isEndSpot = 0
6...[79719:1be03] step 1 unfinished, jumping to end
7...[79719:1be03] step 2 done, moving on
8...[79719:1be03] taking step 3
9...[79719:1be03] animating step to tile <NTTileView: 0x957dbc0; baseClass = UIControl; frame = (268 139; 59 64); layer = <CALayer: 0x957db40>>; id = 29; type = TileTypePeople; isHub = 0; isEndSpot = 0
10...[79719:1be03] step 3 done, moving on

请注意,在第4行开始第二步后,日志报告第6行第一步的“未完成”完成,然后第7行报告第二步完成。但是,第3行在第3行完成。可以在第3行和第6行完成吗?在这种情况下,一个完成了完成= YES而另一个完成= NO,但我也看到这个运行时记录了两个或多个完成的= YES行一步。

什么会导致这样的事情?我甚至不确定从哪里开始寻找bug,或者我只是不明白iOS动画完成块的性质。

奇怪的是,这个代码适用于一个“游戏”,但是一旦应用程序在同一个游戏中启动一个新的“游戏”,代码就开始产生更多“完成”点击,我开始的游戏越多,每次动画获得的“完成”次数越多。感觉就像旧游戏遗留下来的一些垃圾干扰,但静态分析仪中没有泄漏。我很神秘。

更新和解决方案

这个问题是由于旧的废弃游戏板仍在收听通知以移动棋子。即使旧的主板已经发布,它们也没有在游戏结束时专门删除通知请求。由于系统不会立即丢弃释放的对象,因此那些“幽灵”板仍在监听移动棋子的全局通知。即使他们对我们“死了”,他们还活着,可以回应并争夺这些典当的动画!

解决方案是在我们发布之前让每个板[[NSNotificationCenter defaultCenter] removeObserver:self]

2 个答案:

答案 0 :(得分:1)

查看问题的更新。这个问题最终是关于第一次调用pawns从我们的董事会视图的旧发布副本调用的通知。请注意,通知在对象释放后仍然存在,请确保在完成对象时显式删除通知请求!

答案 1 :(得分:0)

我不确定,但我认为这是因为你在动画结束时改变了同一个runloop中的位置,因此中断了第一个动画。如果你这样做了:

[self performSelector:@selector(takeStep:) withObject:[object that describes step] afterDelay:0.0];

我认为这会解决你的问题。