0

I'm trying to use CFRunLoopRunInMode() to avoid returning in [AFHTTPClient getPath:...] completion blocks.

My code looks like:

NSLog(@"start");
__block BOOL someCondition = NO;
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@"http://domain.com"]];
[client getPath:@"my/path" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"success");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"async log");
        someCondition = YES;
    });
    while (!someCondition) {
        CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, YES);
    }
    NSLog(@"failure");
}];

And I expected the output to be:

start
async log
failure

But instead I only get:

start

CFRunLoopRunInMode() returns kCFRunLoopRunHandledSource, but the dispatch queue never executes the submitted block. If I run the same code outside the completion blocks, the output is as expected.

I cannot figure out why the dispatch queue is not processed when run from completion blocks.

Can someone please throw some light on why this happens?

hectr
  • 481
  • 7
  • 15
  • 1
    That are *completion blocks*. The first block is called when the HTTP request operation has completed, the second block is called when the request failed. - Note that trying to *wait* until some asynchronous operation has finished is often a bad idea, in particular if it blocks the main thread and thus the user interface. – Martin R Apr 15 '13 at 21:00
  • I like to live on the edge;) Seriously, I would really like to know why it behaves like that. – hectr Apr 15 '13 at 21:19

2 Answers2

1

I cannot figure out why the dispatch queue is not processed when run from completion blocks.

Because you didn't "run" the dispatch queue (there is no such thing as "running" a dispatch queue). You ran the run loop. The dispatch queue is related, but is a different thing. Only one block can run at a time on a serial queue (like main). Until your block completes, no other block can be scheduled. There is no API into GCD to circumvent that. This is generally a very good thing because it gives certainty to queue operations that do not always exist on runloop operations.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
1

AFNetwork's success and failure block both scheduled in the main queue, the async block you write in the failure block is also scheduled in the main queue.

Until failure block completed, your GCD sync block will run. Because the 'while' condition will never be false, failure block will never complete and it will never has the chance to be executed.

benka
  • 4,732
  • 35
  • 47
  • 58
Sagi
  • 33
  • 4