如果您的帧数组是动态的,或者数组变大,则任务延续变得有点难以实现。
在第三方库(好吧,只有一个类)的帮助下,它看起来像这样:
首先,定义一个动画任务如下:
- (RXPromise*) animationTaskWithFrame(AnimationFrame* frame)
{
RXPromise* promise = [RXPromise new];
[UIView animateWithDuration:0.5 animations:^{
... // animation block
}
completion:^(BOOL finished) {
[promise fulfillWithValue:@"OK"];
}];
return promise;
}
然后,假设您为 NSArray 实现了一个类别:
typedef RXPromise* ^(unary_async_t)(id param);
@interface NSArray (RXExtension)
- (RXPromise*) forEachApplyTask:(unary_async_t)task;
@end
您可以按如下方式运行框架:
-(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*/);
}
如果要在全部完成之前取消动画:
// elsewhere:
- (void) viewWillDisappear:(BOOL)animated {
[self.myAnimationFramesPromise cancel];
}
类的实现如下所示。注意,这是一个通用实现,它只是按顺序为数组中的每个元素串行调用由块任务指定的异步函数。所以,这也是一个可以在其他地方重复使用的工具——不仅仅是用于执行动画。
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 可在 GitHub 上获得:RXPromise。披露:我是作者。