If your array of frames are dynamic, or the array becomes large, the task continuation becomes a bit unwieldy to implement.
With a help of a third party library (well, just one class) it can look like this:
First, define an animation task as follows:
- (RXPromise*) animationTaskWithFrame(AnimationFrame* frame)
{
RXPromise* promise = [RXPromise new];
[UIView animateWithDuration:0.5 animations:^{
... // animation block
}
completion:^(BOOL finished) {
[promise fulfillWithValue:@"OK"];
}];
return promise;
}
Then, assuming you implemented a category for NSArray:
typedef RXPromise* ^(unary_async_t)(id param);
@interface NSArray (RXExtension)
- (RXPromise*) forEachApplyTask:(unary_async_t)task;
@end
You can run your frames as follows:
-(void)animateImageView
{
NSArray* myAnimationFrames = @[frame1,frame2,frame3,frame4,frame5];
// start the animations asynchronously:
self.myAnimationFramesPromise = [myAnimationFrames forEachApplyTask:^RXPromise*(id frame){
return [self animationTaskWithFrame:frame];
}];
// When finished, then:
self.myAnimationFramesPromise.then(^id(id result){
// All animations finished.
NSLog(@"Result: %@", result); // prints @"Finished"
return nil;
}, nil /* error handler*/);
}
If you want to cancel the animations before all finished:
// elsewhere:
- (void) viewWillDisappear:(BOOL)animated {
[self.myAnimationFramesPromise cancel];
}
The implementation of the category is shown below. Note, this is a generic implementation, it simply serially invokes the asynchronous function specified by a block task for each element in the array in order. So, this is a tool which can be reused elsewhere, too - not just for performing animations.
static RXPromise* do_apply_each(NSEnumerator* iter, RXPromise* promiseResult, unary_async_t task)
{
if (promiseResult.isCancelled) {
return promiseResult;
}
id obj = [iter nextObject];
if (obj == nil) {
[promiseResult fulfillWithValue:@"Finished"];
return promiseResult;
}
promiseResult = task(obj).then(^id(id result){
return do_apply_each(iter, promiseResult, task);
}, ^id(NSError*error){
return error;
});
return promiseResult;
}
@implementation NSArray (RXExtension)
- (RXPromise*) forEachApplyTask:(unary_async_t)task {
RXPromise* promise = [RXPromise new];
NSEnumerator* iter = [self objectEnumerator];
return do_apply_each(iter, promise, task);
}
@end
RXPromise is available at GitHub: RXPromise. Disclosure: I'm the author.