Last active
October 30, 2016 09:50
-
-
Save couchdeveloper/6155227 to your computer and use it in GitHub Desktop.
Asynchronous Pattern with GCD Part I
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
Objective: | |
Asynchronously transform or process an array of items - one after the | |
other and return the result of each transform in an array. | |
Synopsis: | |
void transform_each(NSArray* inArray, unary_async_t task, completion_t completion); | |
*/ | |
#import <Foundation/Foundation.h> | |
#import <dispatch/dispatch.h> | |
/** | |
Typedef of a generic completion handler for an asynchronous task. | |
The parameter _result_ is the eventual result of the asynchronous | |
task. In case the task has been failed _result_ SHALL be an | |
NSError object. | |
*/ | |
typedef void (^completion_t)(id result); | |
/** | |
Typedef for an asynchronous "transform" function. It's an | |
unary block taking an input as parameter and signals | |
the eventual result via a completion handler. | |
*/ | |
typedef void (^unary_async_t)(id input, completion_t completion); | |
/** | |
`transform_each` sequentially applies an asynchronous transform function | |
to each object in the input array _inArray_ and signals the result as an | |
array containing the result of each transform applied to the input object. | |
Function `transform_each` is itself a asynchronous function, that is, | |
its eventual result will be signaled to the client through a completion | |
handler. | |
The result array contains the transformed objects in order of the | |
corresponding input array. | |
*/ | |
void transform_each(NSArray* inArray, unary_async_t task, completion_t completion); | |
// implementation | |
static void do_each(NSEnumerator* iter, unary_async_t task, NSMutableArray* outArray, completion_t completion) | |
{ | |
id obj = [iter nextObject]; | |
if (obj == nil) { | |
if (completion) | |
completion([outArray copy]); | |
return; | |
} | |
task(obj, ^(id result){ | |
[outArray addObject:result]; | |
do_each(iter, task, outArray, completion); | |
}); | |
} | |
void transform_each(NSArray* inArray, unary_async_t task, completion_t completion) { | |
NSMutableArray* outArray = [[NSMutableArray alloc] initWithCapacity:[inArray count]]; | |
NSEnumerator* iter = [inArray objectEnumerator]; | |
do_each(iter, task, outArray, completion); | |
} | |
/******************************************************************************* | |
Example | |
*******************************************************************************/ | |
// A Category for NSArray | |
@interface NSArray (AsyncExtension) | |
- (void) async_forEachApplyTask:(unary_async_t) task completion:(completion_t) completion; | |
@end | |
@implementation NSArray (AsyncExtension) | |
- (void) async_forEachApplyTask:(unary_async_t) task completion:(completion_t) completion { | |
transform_each(self, task, completion); | |
} | |
@end | |
// An example transform: | |
unary_async_t capitalize = ^(id object, completion_t completion) { | |
dispatch_async(dispatch_get_global_queue(0, 0), ^{ | |
sleep(1); | |
id result; | |
if ([object respondsToSelector:@selector(capitalizedString)]) { | |
NSLog(@"processing: %@", object); | |
result = [object capitalizedString]; | |
} | |
else { | |
result = [NSError errorWithDomain:@"NSObject" | |
code:-1 | |
userInfo:@{NSLocalizedFailureReasonErrorKey: @"object does not respond to `capitalizedString`"}]; | |
} | |
if (completion) | |
completion(result); | |
}); | |
}; | |
int main(int argc, const char * argv[]) | |
{ | |
@autoreleasepool { | |
dispatch_semaphore_t sem = dispatch_semaphore_create(0); | |
NSArray* input = @[@"a", @"b", @"c"]; | |
[input async_forEachApplyTask:capitalize completion:^(id result) { | |
NSLog(@"Result: %@", result); | |
dispatch_semaphore_signal(sem); | |
}]; | |
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment