Skip to content

Instantly share code, notes, and snippets.

@NikolayShubenkovProgSchool
Last active June 29, 2016 09:23
Show Gist options
  • Save NikolayShubenkovProgSchool/6c458413ec3e91796fa964c36a0f6648 to your computer and use it in GitHub Desktop.
Save NikolayShubenkovProgSchool/6c458413ec3e91796fa964c36a0f6648 to your computer and use it in GitHub Desktop.
typedef NS_ENUM(NSInteger, MDSUpdateTaskType) {
MDSUpdateTaskTypePrices,
MDSUpdateTaskTypeEditorials
};
typedef NS_ENUM(NSInteger, MDSUpdateTaskState) {
MDSUpdateTaskStateWaitingToStart,
MDSUpdateTaskStateUpdating,
MDSUpdateTaskStateSucceed,
MDSUpdateTaskStateFailed
};
@class MDSUpdateTask;
typedef void(^MDSTaskExcecuteBlock)(MDSUpdateTask *task);
/**
* Task which updates itself. On Success it calls next task;
*/
@interface MDSUpdateTask : NSObject
@property (nonatomic, copy) MDSTaskExcecuteBlock succeedBlock;
@property (nonatomic, copy) MDSTaskExcecuteBlock failBlock;
@property (nonatomic, copy) MDSTaskExcecuteBlock excecuteBlock;
@property (nonatomic, strong) MDSUpdateTask *nextTask;
@property (nonatomic, readonly) MDSUpdateTaskType type;
@property (nonatomic, readonly) MDSUpdateTaskState currentState;
//
@property (nonatomic, readonly) BOOL tasksChainSucceded;
+ (instancetype)taskOfType:(MDSUpdateTaskType)type withExcecuteBlock:(MDSTaskExcecuteBlock)excecuteBlock;
//runs only from fail or wailting to start state
- (void)excecuteChain;
//in run block caller can specifie transitions to states
- (void)moveToState:(MDSUpdateTaskState)state;
@end
@interface MDSUpdateTask()
@property (nonatomic, readwrite) MDSUpdateTaskType type;
@property (nonatomic, readwrite) MDSUpdateTaskState currentState;
@end
@implementation MDSUpdateTask
#pragma mark - Properties Overload
- (BOOL)tasksChainSucceded
{
if (self.currentState != MDSUpdateTaskStateSucceed){
return NO;
}
if (self.nextTask == nil){
return YES;
}
return self.nextTask.tasksChainSucceded;
}
- (void)setCurrentState:(MDSUpdateTaskState)currentState
{
if (currentState == _currentState){
return;
}
_currentState = currentState;
switch (_currentState)
{
case MDSUpdateTaskStateSucceed:
{
if (self.succeedBlock){
__typeof__(self) __weak weakSelf = self;
self.succeedBlock(weakSelf);
}
[self.nextTask excecuteChain];
break;
}
case MDSUpdateTaskStateFailed:
{
if (self.failBlock){
__typeof__(self) __weak weakSelf = self;
self.failBlock(weakSelf);
}
}
default:
break;
}
}
#pragma mark - Public
+ (instancetype)taskOfType:(MDSUpdateTaskType)type withExcecuteBlock:(MDSTaskExcecuteBlock)excecuteBlock
{
MDSUpdateTask *task = [MDSUpdateTask new];
task.type = type;
task.excecuteBlock = excecuteBlock;
return task;
}
- (void)excecuteChain
{
//will not excecute successfully chaned tasks
if (self.tasksChainSucceded){
return;
}
switch (self.currentState) {
case MDSUpdateTaskStateFailed:
case MDSUpdateTaskStateWaitingToStart: {
[self excecuteChain];
break;
}
case MDSUpdateTaskStateSucceed:{
[self.nextTask excecuteChain];
}
case MDSUpdateTaskStateUpdating:
//just do nothing
break;
}
}
- (void)excecute
{
self.currentState = MDSUpdateTaskStateUpdating;
__typeof__(self) __weak weakSelf = self;
self.excecuteBlock(weakSelf);
}
- (void)moveToState:(MDSUpdateTaskState)state
{
self.currentState = state;
}
@end
/////////////////////
///////Builder///////
/////////////////////
@class MediastoDataController;
@interface MDSUpdateTask (Build)
+ (NSArray <MDSUpdateTask *> *)buildTasksForController:(MediastoDataController *)controller completion:(void ((^)(BOOL success)))completion;
+ (instancetype)taskOfType:(MDSUpdateTaskType)type forDataController:(MediastoDataController *)controller;
@end
@implementation MDSUpdateTask (Build)
+ (NSArray<MDSUpdateTask *> *)buildTasksForController:(MediastoDataController *)controller completion:(void ((^)(BOOL)))completion
{
MDSUpdateTask *editorials = [self taskOfType:MDSUpdateTaskTypeEditorials forDataController:controller];
MDSUpdateTask *prices = [self taskOfType:MDSUpdateTaskTypePrices forDataController:controller];
editorials.nextTask = prices;
[prices setSucceedBlock:^(MDSUpdateTask *task){
if (completion){
completion(YES);
}
}];
NSArray *tasks = @[editorials,prices];
MDSTaskExcecuteBlock fail = ^(MDSUpdateTask *task){
if (completion){
completion(NO);
}
};
for (MDSUpdateTask *task in tasks){
task.failBlock = fail;
}
return tasks;
}
+ (instancetype)taskOfType:(MDSUpdateTaskType)type forDataController:(MediastoDataController *)controller
{
switch (type) {
case MDSUpdateTaskTypePrices:
{
return [self p_pricesTaskForController:controller];
}
case MDSUpdateTaskTypeEditorials:
{
return [self p_editorialsTaskForController:controller];
}
default:
NSParameterAssert(NO);
}
}
+ (instancetype)p_pricesTaskForController:(MediastoDataController *)controller
{
return [MDSUpdateTask taskOfType:MDSUpdateTaskTypePrices
withExcecuteBlock:^(MDSUpdateTask *task) {
[controller requestMaterialPricesWithCompletion:[self p_finishForListBlockAndTask:task]];
}];
}
+ (instancetype)p_editorialsTaskForController:(MediastoDataController *)controller
{
return [MDSUpdateTask taskOfType:MDSUpdateTaskTypeEditorials
withExcecuteBlock:^(MDSUpdateTask *task) {
[controller getEditorialOfficesWithCompletion:[self p_finishForListBlockAndTask:task]];
}];
}
+ (RequrestListCompletionBlock)p_finishForListBlockAndTask:(MDSUpdateTask *)task
{
return ^(NSArray *list, NSError *error) {
if (error){
[task moveToState:MDSUpdateTaskStateFailed];
return ;
}
[task moveToState:MDSUpdateTaskStateSucceed];
};
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment