iosobjective-cobjective-c-blocksafnetworkingcfrunloop

CFRunLoopRunInMode() within AFHTTPClient success and failure blocks


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?


Solution

  • 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.