NSNotification наблюдается выпущенных объектов - PullRequest
4 голосов
/ 31 декабря 2011

См. Обновление ниже ... хотя изначально это было похоже на проблему с анимацией, оказалось, что это была проблема с уведомлениями.Осторожно: 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];
            }
        }];
    }
}

Это рекурсивный метод, который изначально запускается с шагом = 1 и массивом «плиток» для пешки игрока для анимации.После завершения каждого шага метод вызывается рекурсивно, чтобы выполнить следующий шаг.Когда в массиве заканчиваются тайлы, работа выполнена.В завершенном блоке мы либо делаем следующий шаг, либо (если анимация не была закончена) просто переходим к последней плитке.Вот журнал одного прогона ...

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. Однако шаг 1 был выполнен в строке 3. Как его можно выполнить как в строке 3, так и в строке 6?В этом случае один был завершен с готовым = YES, а другой с завершенным = НЕТ, но я также видел этот прогон с двумя или более линиями готового = ДА, зарегистрированными для одного шага.

Что могло бы вызвать что-то вродеэтот?Я даже не уверен, с чего начать поиск ошибки, или, возможно, я просто не понимаю природу блока завершения для анимации iOS.

Странно то, что этот код отлично работает для одной "игры", но как только приложение запускает новую" игру "в то же время, код начинает производить больше" завершающих "обращений, чем больше игр я запускаю, тем больше" завершающих "обращений я получаю за анимацию.Такое ощущение, что какой-то мусор, оставшийся от старых игр, мешает, но утечки в статическом анализаторе не видны.Я озадачен.

Обновление и решение

Эта проблема была связана с тем, что старые сброшенные игровые поля все еще слушали уведомления о перемещении пешек.Несмотря на то, что старые доски были выпущены, они не удаляли запросы уведомлений по окончании игр.Поскольку выпущенные объекты не сразу отбрасываются системой, эти «призрачные» доски все еще ожидали глобального уведомления о перемещении пешек.И хотя они были «мертвы» для нас, они были достаточно живы, чтобы отвечать и сражаться за анимацию пешек!

Решением было сделать каждую доску [[NSNotificationCenter defaultCenter] removeObserver:self] до того, как мы ее выпустим.

Ответы [ 2 ]

1 голос
/ 01 января 2012

см. Обновление к вопросу.Эта проблема в конечном итоге касалась уведомлений, которые сначала вызывали пешек, чтобы они перезванивали из старых выпущенных копий нашего представления на доске.Остерегайтесь, уведомления выживают после освобождения объектов, обязательно удалите запросы уведомлений, когда вы закончите с объектами!

0 голосов
/ 31 декабря 2011

Я не уверен, но я думаю, что это связано с тем, что вы меняете позицию в том же цикле выполнения, когда заканчивается анимация, поэтому прерываете первую анимацию.Если бы вы сделали это:

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

Я думаю, это решит вашу проблему.

...