Skip to content

Instantly share code, notes, and snippets.

@couchdeveloper
Last active October 30, 2016 09:50
Show Gist options
  • Save couchdeveloper/6155227 to your computer and use it in GitHub Desktop.
Save couchdeveloper/6155227 to your computer and use it in GitHub Desktop.
Asynchronous Pattern with GCD Part I
/**
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