0

I noticed that my application is connecting to remote resources way slower than web browsers, or cURL and decided to do some digging.

I've been using NSURLSession sessionWithConfiguration:delegate: to handle server responses, and decided to try instead using NSURLSession dataTaskWithRequest:completionHandler:. The test methods are below:

-(void)connectWithDelegate:(NSString *)url
{
    semaphore = dispatch_semaphore_create(0);
    session = [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration]
                                            delegate: self
                                       delegateQueue: nil];

    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: url]
                                                       cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
                                                   timeoutInterval: 60.0];


    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest: req];

    [dataTask resume];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

- (void)connectWithCompletionHandler:(NSString *)url
{
    semaphore = dispatch_semaphore_create(0);
    session = [NSURLSession sharedSession];
    NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: url]
                                                       cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
                                                   timeoutInterval: 60.0];

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:req completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error){
        if (!error)
            dispatch_semaphore_signal(semaphore);
    }];

    [dataTask resume];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

Running these tests repeatedly with a range of different network conditions, the connectWithCompletionHandler: method consistently outperforms connectWithDelegate:. On slow connections it can be as much as 6 times faster to return.

The full test code can be found here.

Running this test over 20 iterations on a 5Mb/s link with 50 ms latency yields an average connection time of 0.6 seconds for connectWithCompletionHandler: and 2 seconds for connectWithDelegate:

What accounts for the difference in response time between these two methods...?

j b
  • 5,147
  • 5
  • 41
  • 60
  • What do you want to compare? `[NSURLSession sharedSession]` against recreating a session for each request, or `-[NSURLSession dataTaskWithRequest:]` against `-[NSURLSession dataTaskWithRequest:completionHandler:]`? – Mats Mar 21 '17 at 12:50
  • @Mats Aha! right, I didn't realise creating a new session for each request was significant since the delay is happening between the call to `[dataTask resume]` and the `didReceiveResponse:` method being called. However, if I move `NSURLSession sessionWithConfiguration:delegate:delegateQueue:` to my `init:` then performance improves dramatically. Does this mean actual creation of the `NSURLSession` is deferred until `resume` is called? – j b Mar 21 '17 at 13:08
  • An NSURLSession may re-use the TCP-connection to the server or cache other resources between requests. Some of it may depend on the cache-policy in the response form the server in combination with the cache-policy of the NSURLSession. – Mats Mar 21 '17 at 13:19
  • @Mats thanks. It also seems to make a difference for multiple requests to the same server. Do you want to make your first comment into an answer, and I'll accept it, as this solves the problem? – j b Mar 21 '17 at 14:40

0 Answers0