У меня есть партия вызовов анимации, вызываемая путем перебора массива.Все эти вызовы вложены в инкапсулирующий блок анимации, чтобы они эффективно выполнялись параллельно.У меня также есть блок завершения, и я хочу запустить его только после завершения всех вложенных анимаций.
Проблема заключается в том, что вложенные анимации имеют неизвестную длительность, поэтому я не могу просто рассчитать, какой вызов будет последним завершить, иустановить блок завершения для этого вызова.Точно так же я не могу рассчитать продолжительность и использовать отложенный вызов для блока завершения.
Надеюсь, пример прояснит это.Это (очень упрощенная) версия того, что я пытаюсь сделать:
-(void) animateStuff:(CGFloat)animationDuration withCompletionBlock:(void) (^)(BOOL)completionBlock {
// encapsulating animation block so that all nested animations start at the same time
[UIView animateWithDuration:animationDuration animations:^{
for(MyObject* object in self.array) {
// this method contains other [UIView animateWithDuration calls...
[self animationOfUnknownDurationWithObject:object nestedCompletionBlock:^(BOOL finished) {
// what I effectively what here is:
if(last animation to finish) {
completionBlock(YES);
}
}];
}
}]; // cannot use the completion block for the encapsulating animation block, as it is called straight away
}
Функциональность, предоставляемая использованием dispatch_groups и асинхронного вызова, как описано здесь:
http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
, очевидно, было бы идеальным, однако вызов UIView animateWithDuration сам по себе является асинхронным, и поэтому его вызов в dispatch_group_async не будет работать должным образом.
Я знаю, что мог бы сделать что-то вроде переменной счетчика __block, которая уменьшается в пределах nestedCompletionBlock какспособ определить, какой из них является последним, но в коде, который у меня есть, это довольно грязно (приведенный выше пример упрощен).
Есть ли хороший способ сделать это?Возможно, какой-то способ сделать animateWithDuration синхронно, чтобы он работал с dispatch_group_async?
Работа на iOS 5.0.
ОБНОВЛЕНИЕ:
@ Rob-
Спасибо за ваш ответ!Это почти решает мою проблему - раньше я не рассматривал CATransaction, думаю, мне следовало немного покопаться, прежде чем спрашивать.:)
Однако остается одна проблема.Как я упоминал ранее, мой пример был упрощен, и остающаяся проблема возникает из-за того факта, что у анимации есть вложенные блоки завершения (т. Е. Для связанных анимаций), которые мне нужно включить во вмещающую транзакцию.
Так, например, если я запускаю следующий код:
-(void) testAnim {
NSArray* testArray = [NSArray arrayWithObjects:self.redView, self.blueView, nil];
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
NSLog(@"All animations complete!");
}];
for(UIView* view in testArray) {
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
[CATransaction begin]; {
[CATransaction setCompletionBlock:^{
NSLog(@"2nd stage complete");
}];
NSLog(@"Animation 2nd stage");
[UIView animateWithDuration:2 animations:^{
setX(view, 100);
}];
} [CATransaction commit];
}];
NSLog(@"animation 1st stage");
[UIView animateWithDuration:2 animations:^{
setX(view, 150);
}];
}[CATransaction commit];
}
} [CATransaction commit];
}
я получаю следующий вывод:
2011-12-08 15: 11: 35.828 testProj [51550: f803]анимация 1-й этап
2011-12-08 15: 11: 35.831 testProj [51550: f803] анимация 1-й этап
2011-12-08 15: 11: 37.832 testProj [51550: f803] анимация 2-й этап
2011-12-08 15: 11: 37.834 testProj [51550: f803] Анимация 2-й этап
2011-12-08 15: 11: 37.848 testProj [51550: f803] Все анимации завершены!
2011-12-0815: 11: 39.834 testProj [51550: f803] 2-й этап завершен
2011-12-08 15: 11: 39.851 testProj [51550: f803] 2-й этап завершен
Принимая во внимание, что мне нужно"Все анимации завершены!"событие должно быть запущено только после завершения всех внутренних операций.
Возможно, это связано с тем, что я устанавливаю блоки завершения только на уровне класса и, следовательно, не могу связать каждый блок с определенной операцией?
В любом случае, я все еще не совсем понимаю, и использование перегрузки UIView animateWithDuration с собственным аргументом блока завершения просто вызывает ту же проблему.
Есть идеи?