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