NSNotification, наблюдаемый выпущенными объектами

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

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

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

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

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

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


person EFC    schedule 31.12.2011    source источник


Ответы (2)


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

person EFC    schedule 31.12.2011

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

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

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

person Philippe Sabourin    schedule 31.12.2011
comment
Изменение анимированного объекта в блоке завершения разрешено, что на самом деле важно для вложенных и последовательных анимаций. См. обсуждение showHide в iOS Animating Views. руководство для примера. Кроме того, из того, что я вижу в документации performSelector, это эквивалентно вызову селектора, так что это не изменит ситуацию. - person EFC; 31.12.2011
comment
Селектор Perfrom задерживает вызов следующего цикла выполнения, но вы можете быть правы. - person Philippe Sabourin; 31.12.2011
comment
На всякий случай, если я ошибаюсь, я попробовал это. Использование PerformSelector дает именно то поведение, которое я видел раньше. На самом деле, я пошел еще дальше и использовал уведомления вместо PerformSelector, но все равно столкнулся с той же проблемой. - person EFC; 31.12.2011
comment
Извините, я не заметил, что вы сказали, что больше игр вызывает больше проблем. Вы можете опубликовать код, который создает игры и вызывает это представление? - person Philippe Sabourin; 31.12.2011
comment
Код игры на самом деле довольно сложен, и если вам действительно интересно его увидеть, я, вероятно, мог бы передать вам zip-файл индивидуально, просто не хочу связывать с этим StackOverflow. Однако ни статический анализатор, ни инструменты не обнаруживают утечек в коде игры. Но, да, я тоже там охочусь, просто не знаю, что искать. - person EFC; 31.12.2011
comment
Отправьте zip-файл вашего проекта на электронную почту в моем профиле, и я посмотрю. Мне интересно посмотреть, почему это произойдет. - person Philippe Sabourin; 01.01.2012
comment
давайте продолжим это обсуждение в чате - person EFC; 01.01.2012