NSURLSessionTask nigdy nie oddzwania po przekroczeniu limitu czasu podczas korzystania z konfiguracji w tle
Używam NSURLSessionDownloadTask
z sesjami w tle, aby spełnić wszystkie moje prośby o odpoczynek. W ten sposób mogę używać tego samego kodu bez konieczności myślenia o mojej aplikacji w tle lub na pierwszym planie.
Mój back-end jest martwy od jakiegoś czasu, i skorzystałem z okazji, aby sprawdzić, jak NSURLSession
zachowuje się z timeouts.
NSURLRequest
lub na NSURLSessionConfiguration
, nigdy nie dostaję żadnego połączenia zwrotnego z iOS mówiąc mi, że prośba skończyła się z limitem czasu.
To znaczy, kiedy zaczynam NSURLSessionDownloadTask
sesję w tle. To samo dzieje się aplikacja znajduje się w tle lub na pierwszym planie.
Przykładowy kod:
- (void)launchDownloadTaskOnBackgroundSession {
NSString *sessionIdentifier = @"com.mydomain.myapp.mySessionIdentifier";
NSURLSessionConfiguration *backgroundSessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:sessionIdentifier];
backgroundSessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
backgroundSessionConfiguration.timeoutIntervalForRequest = 40;
backgroundSessionConfiguration.timeoutIntervalForResource = 65;
NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration:backgroundSessionConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.timeout.com/"]];
request.timeoutInterval = 30;
NSURLSessionDownloadTask *task = [backgroundSession downloadTaskWithRequest:request];
[task resume];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(@"URLSession:task:didCompleteWithError: id=%d, error=%@", task.taskIdentifier, error);
}
Jednak, gdy używam sesji domyślnej, wtedy dostaję błąd wywołania zwrotnego po 30sekundach(timeout, który ustawiłem na poziomie żądania).
Przykładowy kod:
- (void)launchDownloadTaskOnDefaultSession {
NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
defaultSessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
defaultSessionConfiguration.timeoutIntervalForRequest = 40;
defaultSessionConfiguration.timeoutIntervalForResource = 65;
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.timeout.com/"]];
request.timeoutInterval = 30;
NSURLSessionDownloadTask *task = [defaultSession downloadTaskWithRequest:request];
[task resume];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
NSLog(@"URLSession:task:didCompleteWithError: id=%d, error=%@", task.taskIdentifier, error);
}
Nie mogę znaleźć w dokumentacji niczego, co by sugerowało że limit czasu powinien zachowywać się inaczej podczas korzystania z sesji w tle.
Czy ktoś też wpadł na ten problem? To błąd czy funkcja?
Rozważam stworzenie raportu o błędzie, ale zazwyczaj otrzymuję informację zwrotną znacznie szybciej NA SO (kilka minut) niż na bug reporter (sześć miesięcy).
Pozdrawiam,
5 answers
Od iOS8, NSUrlSession w trybie tła nie wywołuje tej metody delegata, jeśli serwer nie odpowiada.
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
Pobieranie / przesyłanie pozostaje bezczynne w nieskończoność.
Delegat ten jest wywoływany na iOS7 z błędem, gdy serwer nie odpowiada.
Ogólnie rzecz biorąc, sesja w tle NSURLSession nie zawiedzie zadania, jeśli coś idzie nie tak na podsłuchu. Raczej nadal szuka dobry czas, aby uruchomić żądanie i ponowić próby w tym czasie. To trwa do czasu wygaśnięcia limitu czasu zasobu (czyli wartości właściwość timeoutIntervalForResource w konfiguracji NSURLSessionConfiguration obiekt używany do utworzenia sesji). Aktualna wartość domyślna dla tego wartość to jeden tydzień!
Cytowane informacje zaczerpnięte z tego źródła
Innymi słowy, zachowanie braku czasu w iOS7 było nieprawidłowe. W kontekście sesji w tle, bardziej interesujące jest, aby nie zawieść natychmiast z powodu sieci problemy. Tak więc od iOS8, zadanie NSURLSession jest kontynuowane, nawet jeśli napotka timeouty i utratę sieci. Trwa on jednak do czasu osiągnięcia timeoutIntervalForResource.
Więc zasadniczo timeoutIntervalForRequest nie będzie działać w tle sesji, ale timeoutIntervalForResource będzie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-21 05:10:52
Limit czasu dla DownloadTask jest wyrzucany przez NSURLSessionTaskDelegate, a nie NSURLSessionDownloadDelegate
Aby wyzwolić limit czasu (-1001) podczas zadania pobierania:
Poczekaj, aż rozpocznie się pobieranie. procentowe pobieranie danych wywoła:
URLSession:downloadTask:didWriteData: totalBytesWritten:totalBytesExpectedToWrite:
Następnie wstrzymaj całą aplikację w debugerze XCode.
Poczekaj 30 sekund.Rozpakuj aplikację za pomocą debugera XCode buttons
Połączenie http z serwera powinno się wyłączyć i wyzwalać:
-1001 "żądanie wygasło."
#pragma mark -
#pragma mark NSURLSessionTaskDelegate - timeouts caught here not in DownloadTask delegates
#pragma mark -
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
if(error){
ErrorLog(@"ERROR: [%s] error:%@", __PRETTY_FUNCTION__,error);
//-----------------------------------------------------------------------------------
//-1001 "The request timed out."
// ERROR: [-[SNWebServicesManager URLSession:task:didCompleteWithError:]] error:Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x1247c42e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://directory.clarksons.com/api/1/dataexport/ios/?lastUpdatedDate=01012014000000, NSErrorFailingURLKey=https://directory.clarksons.com/api/1/dataexport/ios/?lastUpdatedDate=01012014000000, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
//-----------------------------------------------------------------------------------
}else{
NSLog(@"%s SESSION ENDED NO ERROR - other delegate methods should also be called so they will reset flags etc", __PRETTY_FUNCTION__);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-18 16:04:55
Istnieje jedna metoda w UIApplicationDelegate, która poinformuje Cię o procesie w tle.
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
Jeśli jest więcej niż jedna sesja, możesz zidentyfikować swoją sesję przez
if ([identifier isEqualToString:@"com.mydomain.myapp.mySessionIdentifier"])
Używana jest jeszcze jedna metoda, aby okresowo powiadamiać o postępie .Tutaj możesz sprawdzić stan NSURLSession
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
NSURLSessionTaskStateRunning = 0,
NSURLSessionTaskStateSuspended = 1,
NSURLSessionTaskStateCanceling = 2,
NSURLSessionTaskStateCompleted = 3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-25 11:55:13
Podobnie jak ty, aplikacja, nad którą pracuję, zawsze używa sesji w tle. Jedną rzeczą, którą zauważyłem, jest to, że timeout działa poprawnie, jeśli przerywa działające połączenie, tzn. transfer rozpoczął się pomyślnie. Jeśli jednak uruchomię zadanie pobierania adresu URL, który nie istnieje,nie skończy się to.
Biorąc pod uwagę, że mówiłeś, że Twój backend był martwy przez jakiś czas, to brzmi jak to, co widziałeś.
Jest dość łatwy do odtworzenia. Ustaw limit czasu na jakieś 5 sekund. Dzięki poprawnemu adresowi URL otrzymasz pewne aktualizacje postępu, a następnie zobaczysz limit czasu. Nawet z sesją w tle. Z nieprawidłowym adresem URL po prostu zamilknie, gdy tylko zadzwonisz do CV.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-02 04:45:05
Doszedłem do tego samego problemu. Jednym z rozwiązań, które znalazłem, jest użycie dwóch sesji, jednej do pobierania na pierwszym planie przy użyciu domyślnej konfiguracji i jednej do pobierania w tle z konfiguracją w tle. Po przejściu na tło / pierwszy plan Wygeneruj dane wznowienia i przekaż je z jednego do drugiego. Ale zastanawiam się, czy znalazłeś inne rozwiązanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-27 09:07:15