NSURLSessionDataTask время ожидания последующих запросов не работает

Я создаю NSMutableRequest:

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

Тайм-аут устанавливается равным 10 секундам, потому что я не хочу, чтобы пользователь слишком долго ждал ответа. После этого я создаю 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];
}

Проблема заключается в том, что сервер переходит в Gateway Timeout, и это занимает много времени. Я получаю ошибку тайм-аута, и я даю обратную связь пользователю, но все последующие вызовы API не срабатывают одинаково из-за ошибки тайм-аута. Единственный способ остановить это - убить приложение и начать все заново. Есть ли что-то, что я должен сделать, чтобы убить задачу или соединение после ошибки таймаута? Если я не установлю тайм-аут, и я жду, пока не получу код ошибки с сервера, все следующие вызовы будут работать отлично (но пользователь ждет много!).

Я попытался отменить задачу:

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];
}

Ответ 1

Я не видел, чтобы вы возобновили задание, которое вы начали. Вам необходимо объявить:

[task resume];

Эта строка возобновляет задачу, если она приостановлена.

Попробуйте вызвать NSURLSession следующим образом:

[NSURLSession sharedSessison] instead of self.session

и аннулировать сеанс:

 [[NSURLSession sharedSession]invalidateAndCancel];

Из документации Apple:

Когда ваше приложение больше не нуждается в сеансе, сделайте недействительным его, вызвав invalidateAndCancel (чтобы отменить выдающиеся задачи) или finishTasksAndInvalidate (чтобы разрешить выполнение выдающихся задач до того, как они были недействительны).

    - (void)invalidateAndCancel

После недействительности ссылки на объекты делегата и обратного вызова сломана. Объекты сеанса нельзя использовать повторно.

Чтобы разрешить выполнение незавершенных задач до завершения, вместо этого выполните exitTasksAndInvalidate.

  - (void)finishTasksAndInvalidate

Этот метод немедленно возвращается, не дожидаясь завершения задач. Когда сеанс недействителен, новые задачи не могут быть созданы в сеансе, но существующие задачи продолжаются до завершения. После завершения последней задачи и завершения сеанса последнего вызова делегата, ссылки на объекты делегата и обратного вызова нарушены. Объекты сеанса нельзя использовать повторно.

Чтобы отменить все невыполнимые задачи, вместо этого вызовите invalidateAndCancel.

Ответ 2

Вы можете установить таймаут по-другому, как следующий код

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

Ответ 3

Проблема, с которой вы, скорее всего, сталкиваетесь здесь, заключается в том, что ваша задача не отменяет или не завершает работу и, следовательно, удерживает сессию от принятия каких-либо задач. Согласно документации Apple

После создания задачи вы запускаете его, вызывая его метод возобновления. Затем сессия поддерживает сильную ссылку на задачу до тех пор, пока запрос завершается или не выполняется;

Как предложил T_77, попробуйте использовать [NSURLSession sharedSession]

Также еще одна вещь, которую я постараюсь сделать в этот момент, - это выяснить, существует ли цикл сохранения, созданный между объектом сеанса и задачей, с помощью инструментов

Еще одна вещь, которая может случиться, заключается в том, что запрос не сформирован должным образом и не выполняется или не висит. Однажды я столкнулся с подобной проблемой, когда попытался загрузить URL-адрес в веб-представление. Страница не загружалась и не выдавала ошибку. Попробуйте еще раз проверить запрос URL.

Спасибо, Сураджа

Ответ 4

Наиболее вероятной причиной таймаута является либо то, что DNS разрешен на IP-адрес, который не существует, либо что сервер потерпел аварию и нуждается в перезагрузке. В любом случае, если один запрос терпит неудачу с тайм-аутом, большее количество запросов, скорее всего, будет терпеть неудачу с тайм-аутом.

Вам, очевидно, нужно написать свое приложение таким образом, чтобы он мог выжить, когда серверы не отвечают.