Тайм-аут NSURLSessionDataTask, последующие запросы не выполняются

Я создаю NSMutableRequest:

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

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

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

person nicky_1525    schedule 15.07.2015    source источник
comment
Я думаю, вам может потребоваться повторно инициализировать self.req, если есть ошибка/тайм-аут. Хотя не уверен в этом.   -  person Mrunal    schedule 15.07.2015
comment
попробуйте вызвать соединения с приложением POSTMAN в chrome и посмотрите, по-прежнему ли вы получаете ошибку тайм-аута или нет   -  person Teja Nandamuri    schedule 15.07.2015
comment
Вы создаете эту задачу внутри какого-то блока? Или какой-то другой поток, кроме основного потока?   -  person Mayur Deshmukh    schedule 24.07.2015
comment
@nicky Смогли ли вы найти решение. Столкнулся с такой же ситуацией. Я получаю ошибку тайм-аута сервера, ставлю в очередь все запросы и повторяю их, но это всегда терпит неудачу.   -  person Shikha Shah    schedule 21.04.2017


Ответы (4)


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

[task resume];

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

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

[NSURLSession sharedSessison] instead of self.session

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

 [[NSURLSession sharedSession]invalidateAndCancel];

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

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

    - (void)invalidateAndCancel

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

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

  - (void)finishTasksAndInvalidate

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

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

person Teja Nandamuri    schedule 15.07.2015
comment
Да, я забыл резюме здесь в вопросе. Я собираюсь отредактировать его. И единственный метод, который я могу вызвать для задачи, чтобы сделать ее недействительной, — это отменить. Я не вижу других. Я пробовал, но это не решает проблему. Спасибо - person nicky_1525; 15.07.2015
comment
как ты вызываешь отмену? - person Teja Nandamuri; 15.07.2015

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

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

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

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

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

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

person Suraj Sundar    schedule 24.07.2015

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

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

person gnasher729    schedule 17.07.2015
comment
Если я установлю тайм-аут равным 60 вместо 10 секунд, я получу тайм-аут шлюза с сервера, и все запросы, которые я выполняю после этого, будут работать отлично. Проблема в том, что таймаут происходит до ответа от сервера. Все следующие запросы терпят неудачу, пока я не убью приложение. - person nicky_1525; 17.07.2015

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

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