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