5

Ich habe ein Problem, wenn es um ein langsames Backend geht und Daten mit Hintergrundkonfiguration heruntergeladen werden.NSURLSessionDownloadTask wiederholt bei Verwendung der Hintergrundkonfiguration

NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; 
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; 
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithURL:URL]; 
[downloadTask resume]; 

Wenn die Verbindung astablished ist, aber es dauert mehr als 60 Sekunden für es ein Timeout auftritt zurück zu senden Daten. Das ist gut. Das Verhalten, das ich erfahre, ist jedoch, dass ich keinen Fehler erhalte. Die Sitzung sendet nur eine neue Anfrage. "Gib mir Daten wieder". Ich habe keine Ahnung, wo das passiert. Nicht in meinem Code und keine Delegate-Methoden, die ich kenne. Ich habe nur Zugriff auf die Serverprotokolle. Der Server benötigt ungefähr 68 Sekunden, um Daten zurückzusenden, aber die App ignoriert sie einfach, weil sie auf die neue Anfrage wartet.

Eine Lösung besteht darin, den Zeitüberschreitungswert zu erhöhen. Aber ich mag es nicht und es funktioniert nur für iOS 7. Nicht iOS 8.

sessionConfig.timeoutIntervalForRequest = 10 * 60.0; 

Hat jemand einen Einblick in diese? Ich habe diese link about timeout issue for background session hier auf Stackoverflow gefunden. Es ist 10 Monate alt, aber keine Lösungen, nur die Leute stimmen zu.

Antwort

3

Ich habe es geschafft, es zu lösen. Ich sage nicht, dass meine Lösung die Lösung ist, aber es ist eine Lösung.

Das Verhalten, das ich erfahre, ist, dass iOS 7 und iOS 8 Eigenschaften unterschiedlich priorisiert. Ich habe zwei Orte, um diese Timeout-Eigenschaften zu setzen, die NSURLSessionConfiguration und in der NSMutableURLRequest. iOS 7 interessiert sich nicht mehr für die Eigenschaft "Anfragen" und iOS 8 kümmert sich nicht um die Konfigurationseigenschaft. Gerade jetzt meine Lösung sieht wie folgt aus:

NSURLSessionConfiguration *sessionConfig; 
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; 
} 
else { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; 
} 
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) { 
    sessionConfig.timeoutIntervalForRequest = 5 * 60.0; 
} 
_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; 

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; 
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { 
    request.timeoutInterval = 5 * 60.0; 
} 
NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request]; 

Ich denke, man konnte einfach nicht tun, um die Systemversion überprüft und stellen Sie beide Eigenschaften auf den gleichen Wert. Obwohl ich der festen Überzeugung bin, dass weniger Code mehr ist, glaube ich sogar noch stärker daran, dass er Staaten nicht beeinflusst, die nicht betroffen sein müssen. Aber ich würde gerne hören Menschen Meinungen. Und wenn jemand eine bessere Lösung hat, bitte teilen.

Oh noch eine Sache. Der Wiederholungsversuch wird fortgesetzt, bis timeoutIntervalForResource gemäß der Dokumentation den Standardwert von 7 Tagen erreicht. Ich habe das auf 10 Minuten verringert.

sessionConfig.timeoutIntervalForResource = 10 * 60; 

Ich sage nicht, dass es geändert werden sollte. Dies ist eine Entscheidung, die wir für unsere spezifische Umgebung getroffen haben.

aktualisieren

Wir änderten die timeoutIntervalForResource auf den Standardwert von 7 Tagen zurück. Wir haben zum Beispiel Kunden in China und einige von ihnen haben wirklich schlechte Verbindung. Ein Master-Limit von 10 Minuten war nur albern.

Überprüfen Sie Sunkas answer für bessere Code-Qualität. Mein Code-Snippet ist jedoch auf verschiedene Klassen verteilt, so dass ich diesen Ansatz nicht 100% wiederverwenden kann.

+0

Frage: warum Sie Unterscheidung zwischen iOS 8 und iOS 7 schließlich machen Sie? Könnten Sie nicht einfach sowohl timeoutIntervalForRequest als auch timeoutInterval setzen? – dlinsin

6

konnte mich nicht stoppen, hier ist die Antwort ein wenig Refactoring :)

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; 
NSURLSessionConfiguration *sessionConfig; 
float timeout = 5 * 60.0f; 

BOOL iOS8OrNewer = [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0; 
if (iOS8OrNewer) { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; 
    request.timeoutInterval = timeout; 
} 
else { 
    sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier]; 
    sessionConfig.timeoutIntervalForRequest = timeout; 
} 

_backgroundSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil]; 

NSURLSessionDownloadTask *downloadTask = [_backgroundSession downloadTaskWithRequest:request]; 
+2

Sehr schön und einfach zu lesen, danke! Obwohl mein Code-Snippet tatsächlich über zwei separate Klassen verteilt ist, werde ich das anwenden, was ich daraus machen kann :) –

3

Seit iOS8, die NSUrlSession im Hintergrundmodus nicht über diese Delegaten-Methode aufrufen, wenn der Server nicht reagiert. -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error Der Download/Upload bleibt auf unbestimmte Zeit im Leerlauf. Dieser Delegat wird auf iOS7 mit einem Fehler aufgerufen, wenn der Server nicht antwortet.

Im Allgemeinen schlägt eine NSURLSession-Hintergrundsitzung eine Aufgabe fehl, wenn auf der Leitung etwas schief geht. Vielmehr sucht es weiterhin nach einer guten Zeit, um die Anfrage und die Versuche zu dieser Zeit auszuführen. Dies wird fortgesetzt, bis das Ressourcen-Timeout abläuft (dh der Wert der timeoutIntervalForResource-Eigenschaft im NSURLSessionConfiguration-Objekt, das Sie zum Erstellen der Sitzung verwenden). Der aktuelle Standardwert für diesen Wert ist eine Woche! Mit anderen Worten, das Verhalten von fehlgeschlagen für ein Timeout in iOS7 war falsch. Im Kontext einer Hintergrundsitzung ist es interessanter, aufgrund von Netzwerkproblemen nicht sofort zu versagen. Seit iOS8 wird der Task NSURLSession fortgesetzt, selbst wenn Timeouts und Netzwerkverluste auftreten. Es wird jedoch fortgesetzt, bis timeoutIntervalForResource erreicht ist.

Also im Grunde funktioniert timeoutIntervalForRequest nicht im Hintergrund Sitzung aber TimeoutIntervalForResource wird.

Quelle: Apple Forum

Verwandte Themen