0

How to perform number of NSURLConnection sendAsynchronousRequest in order?

I have to do various async request and get a FINAL COMPLETION.

I wanted to perform these actions in a particular order. Lets say

sendAsynchronousRequest2 should be initiated after completion of a sendAsynchronousRequest1 and so on...

ɲeuroburɳ's answer in this question is useful. But, It doesn't solve my problem

Waiting until two async blocks are executed before starting another block

Help will be appreciated

Community
  • 1
  • 1
riyaz
  • 1,093
  • 1
  • 8
  • 21

3 Answers3

2

I did something similar before. I used a custom object that held a NSURLRequest instance and a NSURLConnection style completionHandler. These objects were created and added to a queue.
A helper method dequeues a request and sends it. In the original completionHandler of the NSURLConnection I called the completionHandler of the custom object, then I called the helper method again. Which would then dequeue the next request.

In code that would look like this:

@interface URLRequest: NSObject
@property (strong, nonatomic) NSURLRequest *request;
@property (copy, nonatomic) void (^completionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError);
@end

@implementation URLRequest
@end

 

// viewController Interface
@property (strong) NSMutableArray *requestsQueue;

// implementation
- (BOOL)sendURLRequest {
    if ([self.requestsQueue count] > 0) {
        URLRequest *request = self.requestsQueue[0];
        [NSURLConnection sendAsynchronousRequest:request.request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            NSLog(@"Request to url %@ done", response.URL);

            if (request.completionHandler) {
                request.completionHandler(response, data, connectionError);
            }
            [self.requestsQueue removeObjectAtIndex:0];

            if (![self sendURLRequest]) {
                NSLog(@"Queue Completed");
            }
        }];
        return YES;
    }
    else {
        NSLog(@"All requests send");
        return NO;
    }
}

- (void)addRequestToQueue:(URLRequest *)request {
    if (!self.requestsQueue) {
        self.requestsQueue = [NSMutableArray array];
    }
    BOOL queueWasEmpty = [self.requestsQueue count] == 0;
    [self.requestsQueue addObject:request];

    if (queueWasEmpty) {
        NSLog(@"Start request queue");
        [self sendURLRequest];
    }
}

 

URLRequest *request = [[URLRequest alloc] init];
request.request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
request.completionHandler = ^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    NSLog(@"Request to www.google.com completed with status %ld", (long)((NSHTTPURLResponse *)response).statusCode);
};
[self addRequestToQueue:request];

request = [[URLRequest alloc] init];
request.request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.stackoverflow.com"]];
request.completionHandler = ^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    NSLog(@"Request to www.stackoverflow.com completed with status %ld", (long)((NSHTTPURLResponse *)response).statusCode);
};
[self addRequestToQueue:request];

This is the naive version. You have to think about error (and timeout) handling yourself.

Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247
2

You could do something similar to the following.

Add your NSURLRequests to an NSMutableArray, in the order you want them completed.

Then call 'performRequestQueue' to start them in order:

NSMutableArray *requests = ...

- (void)performRequestQueue {
    NSURLRequest *request = [requests firstObject];
    NSOperationQueue *rQueue = [[NSOperationQueue alloc] init];
    [NSURLConnection sendAsynchronousRequest:request queue:rQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if ([data length] && error == nil) {
            // use data

            // remove current request from queue
            [requests removeObject:[requests firstObject]];
            if (requests.count > 0) {
                // if there are more, start next request
                [self performRequestQueue]
            } else {
                // else queue is complete, do whatever you need to here
                [self queueCompleted];
            }
        } else {
            // no data or error
        }
    }];
}

- (void)queueCompleted {
    // All NSURLConnections completed
}
Chris Stokes
  • 175
  • 9
1

GCD Semaphore can help you.

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
       // some operations 
       dispatch_semaphore_signal(semaphore);
    });

    // You will reach this point only after signal
    dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));

   // for more you just add one more async dispatch
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
       // some operations 
       dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));

In this case you will choose by yourself when block ends, and when you need to go further

Also you can use NSOperationQueue(NSOperation Dependency) or GCD groups

More about semaphore read here - https://developer.apple.com/library/prerelease/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/doc/uid/TP40008079-CH2-SW37

Pavel Gatilov
  • 2,570
  • 2
  • 18
  • 31
  • Sorry, how to do it with more than one `dispatch_async` And what is the final completion? – riyaz Mar 12 '15 at 10:17