nicky_1525
nicky_1525

Reputation: 959

NSURLSessionDataTask timeout subsequent requests failing

I am creating a NSMutableRequest:

self.req = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];

The timeout is set to be 10 seconds because I don't want the user to wait too long to get a feedback. After that I create a NSURLSessionDataTask:

NSURLSessionDataTask *task = [self.session dataTaskWithRequest:self.req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSHTTPURLResponse * httpResp = (NSHTTPURLResponse *)response;
    if (error) {
        // this is where I get the timeout
    } 
    else if (httpResp.statusCode < 200 || httpResp.statusCode >= 300) {
        // handling error and giving feedback
    } 
    else {
        NSError *serializationError = nil;
        NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&serializationError];
    }
    [task resume];
}

The problem is the server goes into Gateway Timeout and it takes a lot of time. I get the timeout error and I give a feedback to the user, but all the following API calls fail in the same way due to timeout error. The only way to stop it is to kill the app and start over. Is there something I should do to kill the task or the connection after a timeout error? If I don't set a timeout and I wait until I receive the error code from the server all the following calls work perfectly (But the user waits a lot!).

I tried to cancel the task:

NSURLSessionDataTask *task = [self.session dataTaskWithRequest:self.req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSHTTPURLResponse * httpResp = (NSHTTPURLResponse *)response;
    if (error) {
        // this is where I get the timeout
        [task cancel];
    } 
    ...
    [task resume];
}

Upvotes: 11

Views: 3407

Answers (4)

Suraj Sundar
Suraj Sundar

Reputation: 19

The problem that you are most probably encountering here is that your task is not cancelling or completing and is hence holding the session from accepting any more tasks. As per Apple's documentation

After you create a task, you start it by calling its resume method. The session then maintains a strong reference to the task until the request finishes or fails;

As T_77 suggested, try using [NSURLSession sharedSession]

Also one more thing I would try to do at this point of time is trying to find out if there is a retain cycle created between the session object and the task, using Instruments

One more thing that could be happening is that the request is not properly formed and is not executing or is hung. I had faced a similar issue once when I tried to load a URL onto a web view. The page was not loading and not throwing an error. Try verifying the url request also once.

Thanks, Suraj

Upvotes: 1

larva
larva

Reputation: 5148

You may set timeout in different way like following code

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.timeoutIntervalForRequest = timeout;
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:nil delegateQueue:nil];

Upvotes: 0

gnasher729
gnasher729

Reputation: 52538

The most likely cause for a timeout is either that DNS resolved to an IP address that didn't exist, or that the server has crashed and needs rebooting. In any case, if one request fails with timeout, more requests are reasonably likely to fail with timeout as well.

You obviously need to write your application in such a way that it can survive when it's servers don't reply.

Upvotes: 0

Teja Nandamuri
Teja Nandamuri

Reputation: 11201

I didnt see you resume the task you started. You need to declare:

[task resume];

This line Resumes the task, if it is suspended.

Try to call the NSURLSession as follows:

[NSURLSession sharedSessison] instead of self.session

and invalidate the session by:

 [[NSURLSession sharedSession]invalidateAndCancel];

From Apple's Documentation:

When your app no longer needs a session, invalidate it by calling either invalidateAndCancel (to cancel outstanding tasks) or finishTasksAndInvalidate (to allow outstanding tasks to finish before invalidating the object).

    - (void)invalidateAndCancel

Once invalidated, references to the delegate and callback objects are broken. Session objects cannot be reused.

To allow outstanding tasks to run until completion, call finishTasksAndInvalidate instead.

  - (void)finishTasksAndInvalidate

This method returns immediately without waiting for tasks to finish. Once a session is invalidated, new tasks cannot be created in the session, but existing tasks continue until completion. After the last task finishes and the session makes the last delegate call, references to the delegate and callback objects are broken. Session objects cannot be reused.

To cancel all outstanding tasks, call invalidateAndCancel instead.

Upvotes: 5

Related Questions