1

I am new to asynchronous callbacks and have been given differing advice. I need to perform asynchronous callbacks and after many hours of research I still do not know if I should use blocks or GCD and queues. Any pointers would be welcome.

OK. So what I was really asking is:

"in order to use an 'asynchronous' callbacks, do I need to use GCD and queues?"

What I am gathering from the answers is that the answer is YES. Definitely GCD and queues inside of blocks.

My confusion stemmed from the fact that I had been given the direction that all I needed was a block, like the code below:

[UIView animateWithDuration:.4f
                 animations:^{
                     flashView.alpha = 0.f;
                 }
                 completion:^(BOOL finished){
                     [flashView removeFromSuperview];
                 }
 ];

But what I am seeing in the answers here is that the above block in not sufficient for making 'asynchronous' callbacks. Instead I DO in-fact need to use GCD and queues inside a block, like the code below:

- (void)invokeAsync:(id (^)(void))asyncBlock resultBlock:(void (^)(id))resultBlock errorBlock:(void (^)(id))errorBlock {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        id result = nil;
        id error = nil;
        @try {
            result = asyncBlock();
        } @catch (NSException *exception) {
            NSLog(@"caught exception: %@", exception);
            error = exception;
        }
        // tell the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSAutoreleasePool *secondaryPool = [[NSAutoreleasePool alloc] init];
            if (error != nil) {
                errorBlock(error);
            } else {
                resultBlock(result);
            }
            [secondaryPool release];
        });
        [pool release];
    });
}
Jano
  • 62,815
  • 21
  • 164
  • 192
Patricia
  • 5,019
  • 14
  • 72
  • 152
  • 2
    It's not too clear what you're asking. GCD is entirely built around the idea of submitting blocks to queues. You can't really separate GCD from blocks and queues, they go together. – Andrew Madsen Oct 11 '13 at 05:03
  • @AndrewMadsen Technically you *can* use GCD with functions, although who would want to!? – Jasper Blues Oct 11 '13 at 07:07
  • @JasperBlues, yeah, I thought of noting that. I've never actually seen anyone use those function-based dispatch functions. I guess they're useful if you're using libdispatch in an environment without blocks? Anyway, for all normal intents and purposes, especially to a beginner, GCD is always used with blocks. – Andrew Madsen Oct 11 '13 at 14:49
  • @AndrewMadsen Read my updated explanation. You will be able to understand my confusion on this topic. So what you are telling me is that I do need to used GCD and queues with blocks in order to make an 'asynchronous' callback. I cannot just use a block without GCD and queues. – Patricia Oct 11 '13 at 15:24
  • @JasperBlues Read my updated explanation. You will be able to understand my confusion on this topic. So what you are telling me is that I do need to used GCD and queues with blocks in order to make an 'asynchronous' callback. I cannot just use a block without GCD and queues. – Patricia Oct 11 '13 at 15:25
  • @Lucy - you *do* need to put your code on a different thread then the main thread. There's many ways to do this. 1) Use on of the many threading interfaces available - pthreads (plain C), NSThead, etc, 2) Use NSOperation 3) Use GCD. . options 2 and 3 are higher abstractions, so you don't have to worry about the nitty gritty details. . . Many people find GCD feels more natural than NSOperation. So in summary - blocks won't help directly, they just make the interface nicer.Many block-based API methods will dispatch to another thread - the only way to tell if this is the case, is from the docs – Jasper Blues Oct 11 '13 at 19:53
  • @AndrewMadsen I've never seen it either. I just thought it was an amusing point of contention. – Jasper Blues Oct 11 '13 at 19:59

2 Answers2

3

An asynchronous callback is one where your current thread keeps executing statements, and you detach the execution of code in a different thread to be ran later.

There are several technologies to accomplish this. On this example I'm calling the method cacheImage:, with parameter image (just an example) in 4 different asynchronous ways.

// 1. NSThread
[NSThread detachNewThreadSelector:@selector(cacheImage:) toTarget:self withObject:image];

// 2. performSelector...
[self performSelectorInBackground:@selector(cacheImage:) withObject:image];

// 3. NSOperationQueue
NSInvocationOperation *invOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(cacheImage:) object:image];
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
[opQueue addOperation:invOperation];

// 4. GCD
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self cacheImage:image];
});

By far the more simple way is to use GCD because it already has a thread ready for you to use, instead having to create it yourself with the other options.

However, because blocks are implemented as objects, you could indeed use blocks without GCD, for example:

// block definition
typedef void (^hello_t)();

// method that uses a block as parameter
-(void) runBlock:(hello_t)hello {
    hello();
}

// asynchronous execution of a block
[NSThread detachNewThreadSelector:@selector(runBlock) toTarget:self withObject:^(){
    NSLog(@"hi");
}];

PS: you don't need to use NSAutoreleasePool manually unless you create many many objects and you want to free memory immediately. Also, @try @catch are rarely used in Objective-C

Jano
  • 62,815
  • 21
  • 164
  • 192
  • Thank you, Jano. Your explanation is very thorough and helpful to me in understanding how to use 'asynchronous' callbacks. – Patricia Oct 12 '13 at 16:31
2

Not any point of confusion here. GCD also has a block execution. GCD API, which supports the asynchronous execution of operations at the Unix level of the system.

Block objects are a C-level syntactic and runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. A block can therefore maintain a set of state (data) that it can use to impact behavior when executed.

Apple designed blocks with the explicit goal of making it easier to write programs for the Grand Central Dispatch threading architecture, although it is independent of that architecture and can be used in much the same way as closures in other languages. Apple has implemented blocks both in their own branch of the GNU Compiler Collection and in the Clang LLVM compiler front end. Language runtime library support for blocks is also available as part of the LLVM project.

Therefore you can use any one of them given you same functionality.

Tirth
  • 7,801
  • 9
  • 55
  • 88
  • So basically you are telling me that I can use either to perform the same asynchronous behavior? Thank you, Lucy – Patricia Oct 11 '13 at 05:19
  • 1
    @Lucy - If you use GCD, you'll be using blocks to pass in what gets executed asynchronously. – Jasper Blues Oct 11 '13 at 07:09
  • @iAmbitious - I thought by your comment that a block was sufficient for making an 'asynchronous' call back. Read my updated explanation. You will be able to understand my confusion on this topic. So what you are telling me is that I do need to used GCD and queues with blocks in order to make an 'asynchronous' callback. I cannot just use a block without GCD and queues. – Patricia Oct 11 '13 at 15:27
  • A block is just a function with some stuff tacked onto it. Calling it is no different from calling a function. The async part has to be done with threads or queues. – Catfish_Man Oct 11 '13 at 16:26
  • However, other code may use a queue for you internally. That UIKit method likely does. – Catfish_Man Oct 11 '13 at 16:29