Search code examples
iosnsurlconnectionnsurlsession

Best practice to replace a synchronous NSURLConnection with NSURLSession


As

NSURLConnection sendSynchronousRequest:returningResponse:error:&connectionError

is set deprecated I will have to replace an Importer I wrote a long time ago.

The Importer does the following:

  1. It fetches data from API-A. The data there can be on multiple pages.
  2. It uses the data from the first fetch (also multipage) to query data from API-B and merges
  3. Results from the API-B query will be merged with data from API-A

I implemented this with a background-operation where I use methods for each API which called recursively if there are mulitple pages for the request.

But as NSURLSession does not support synchronous request I currently only see the option to have lot of overhead (e.g. iVars) control what's called in the completion block (e.g. next Page or start to query API-B).

So, what would be an elegant solution to bring this to NSURLSession.

NB: Just to make sure, my previous solution does not block the main thread at all. But back then it was the easiest way to control the merge of two sources.


Solution

  • This answer is not supposed to be best practice. It was just practical for me.

    Faced with the situation when a bunch of synchronous requests is executed in background and the order of execution matters I've ended up using the following:

    SyncRequestSender.h

    #import <Foundation/Foundation.h>
    
    @interface SyncRequestSender : NSObject
    
    + (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                     returningResponse:(NSURLResponse **)response
                                 error:(NSError **)error;
    
    @end
    

    SyncRequestSender.m

    #import "SyncRequestSender.h"
    
    @implementation SyncRequestSender
    
    + (NSData *)sendSynchronousRequest:(NSURLRequest *)request
                     returningResponse:(NSURLResponse **)response
                                 error:(NSError **)error
    {
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_enter(group);
    
    
        NSError __block *err = NULL;
        NSData __block *data;
        NSURLResponse __block *resp;
    
        [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                         completionHandler:^(NSData* _data, NSURLResponse* _response, NSError* _error) {
            resp = _response;
            err = _error;
            data = _data;
            dispatch_group_leave(group);
    
        }] resume];
    
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
        if (response)
        {
            *response = resp;
        }
        if (error)
        {
            *error = err;
        }
    
        return data;
    }
    
    @end