Show Menu

Need an iOS Developer?

Submit your 30 day Job Listing for FREE

Recently I read a tweet from Landon Fuller that showed the disassembly of +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:] mainly as a simple call to +[NSURLConnection sendSynchronousRequest:returningResponse:error:] dispatched on a global queue.

I have never been a big fan of this asynchronous request API on NSURLConnection since it lacks a major feature in my opinion: cancellation.

Since writing a simple URL connection as an NSOperation subclass is not too hard, let’s go and build it!

First thing first, we will want our method look as close as possible to the one previously mentioned. We will thus provide a new method in a category on NSURLConnection:

+ (id)sendActuallyAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *connectionError))completionHandler;

This method returns an opaque object that can be used in order to cancel the request by mean of another method

+ (void)cancelActuallyAsynchronousRequest:(id)connection;

The implementation is fairly simple: we create a URL connection operation with the request that we dispatch to a global queue. We then have a dependent operation that retrieves the connection’s results and invoke the completion handler. This operation is dispatched to the provided queue or the main queue if none is provided.
Finally, the connection operation is returned.

+ (id)sendActuallyAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *connectionError))completionHandler
    queue = queue ? : [NSOperationQueue mainQueue];
    completionHandler = completionHandler ? : ^ (NSURLResponse *response, NSData *data, NSError *connectionError) {};

    _NSURLActuallyAsynchronousURLConnectionOperation *connectionOperation = [[_NSURLActuallyAsynchronousURLConnectionOperation alloc] initWithRequest:request];
    [[self _actuallyAsynchronousURLConnectionOperationQueue] addOperation:connectionOperation];

    NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^ {
        NSURLResponse *response = [connectionOperation response];
        NSData *data = [NSData dataWithData:[connectionOperation data]];
        NSError *connectionError = [connectionOperation error];

        completionHandler(response, data, connectionError);
    [completionOperation addDependency:connectionOperation];
    [queue addOperation:completionOperation];

    return connectionOperation;

Cancellation is also very easy since the opaque object we returned is the operation itself, we simply need to call cancel on it.

+ (void)cancelActuallyAsynchronousRequest:(id)asynchronousRequest
    NSParameterAssert([asynchronousRequest isKindOfClass:[_NSURLActuallyAsynchronousURLConnectionOperation class]]);

    _NSURLActuallyAsynchronousURLConnectionOperation *operation = (_NSURLActuallyAsynchronousURLConnectionOperation *)asynchronousRequest;
    [operation cancel];

The implementation of the _NSURLActuallyAsynchronousURLConnectionOperation operation is also fairly basic. This operation is concurrent so that we can benefit from the asynchronous nature of NSURLConnection.

We create a URL connection in the initialiser and provide an operation queue as the connection delegate queue so that we don’t need to provide a runloop (usually by using the main runloop or by creating a connection thread running the runloop and that is shared by all the connection operations).

The implementation of start simply starts the connection. Similarly, the implementation of cancel cancels the connection and finish the operation.

We create a mutable data to which we append data each time it is received. This is not an ideal situation when dealing with large response bodies but it is the API provided by NSURLConnection and for the sake of this example we will try to mimic it as much as possible.

Any failure on the connection will be reported as an NSError to the delegate, in which case we store the error and finish the operation. Similarly, when the connection finishes loading we can nicely finish the operation.

[socialRansom link=””]

And that’s it! As you can see, providing a simple asynchronous and cancellable asynchronous request built as an operation on top of NSURLConnection is not so hard.

having issues?

We have a Questions and Answer section where you can ask your iOS Development questions to thousands of iOS Developers.

Ask Question

FREE Download!

Get your FREE Swift 2 Cheat Sheet and quick reference guide PDF download when you sign up to SwiftMonthly

Sharing is caring

If you enjoyed this tutorial, please help us and others by sharing using one of the social media buttons below.

Written by:

I’m Damien DeVille, a software engineer working at Realmac Software in sunny Brighton, UK. I build Ember for Mac. I mostly work on Cocoa projects but enjoy some web development once in a while. I am also a real debugger aficionado. I’m also an avid reader and very passionate about languages and linguistics. I graduated from UCL with a double MSc in Computer Science and Financial Engineering