5

Ho un problema quando si tratta di un back-end lento e il download dei dati con la configurazione in background.NSURLSessionDownloadTask continua a riprovare quando si utilizza Configurazione sfondo

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

Se la connessione è astablished ma ci vuole più di 60 secondi per inviare di nuovo i dati si verifica un timeout. Questo va bene. Tuttavia, il comportamento che ho riscontrato è che non ricevo un errore. La Sessione invia appena una nuova richiesta. "Dammi di nuovo i dati". Non ho idea di dove questo accada. Non nel mio codice e non vengono chiamati metodi delegati di cui sono a conoscenza. Ho solo accesso ai log del server. Richiede al server circa 68 secondi per inviare i dati, ma l'app lo ignora semplicemente perché è in attesa della nuova richiesta.

Una soluzione è aumentare il valore di timeout. Ma non mi piace e funziona solo per iOS 7. Non per iOS 8.

sessionConfig.timeoutIntervalForRequest = 10 * 60.0; 

Qualcuno ha qualche idea in questo? Ho trovato questo link about timeout issue for background session qui su StackOverflow. Ha 10 mesi ma non ci sono soluzioni, solo le persone sono d'accordo.

risposta

3

Sono riuscito a risolverlo. Non sto dicendo che la mia soluzione è la soluzione ma è la soluzione a.

Il comportamento che sto vivendo è che iOS 7 e iOS 8 danno priorità alle proprietà in modo diverso. Ho due posizioni per impostare queste proprietà di timeout, NSURLSessionConfiguration e nel NSMutableURLRequest. iOS 7 non potrebbe interessare di meno alla proprietà delle richieste e iOS 8 non potrebbe importare di meno della proprietà delle configurazioni. In questo momento la mia soluzione è simile al seguente:

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

Credo che non si poteva solo fare i controlli VersioneSistema e impostare entrambe le proprietà per lo stesso valore. Anche se credo fermamente che meno codice è più credo ancora più fortemente nel non influenzare gli stati che non hanno bisogno di essere influenzati. Tuttavia mi piacerebbe sentire la gente opinioni. E se qualcuno ha una soluzione migliore per favore condividi.

Oh un'altra cosa. La parte riprovata continuerà a verificarsi fino a quando timeoutIntervalForResource raggiunge il valore predefinito di 7 giorni in base alla documentazione. Ho diminuito questo a 10 minuti.

sessionConfig.timeoutIntervalForResource = 10 * 60; 

Non sto dicendo che dovrebbe essere cambiato. Questa è una decisione che abbiamo preso per la nostra specifica configurazione ambientale.

Aggiornamento

abbiamo cambiato il timeoutIntervalForResource indietro al valore predefinito di 7 giorni. Ad esempio, abbiamo clienti in Cina e alcuni di loro hanno una connessione davvero scadente. Un limite principale di 10 minuti era semplicemente sciocco.

Assicurati di controllare Sunkas answer per una migliore qualità del codice. Il mio snippet di codice, tuttavia, è distribuito su classi diverse, quindi non posso riutilizzare tale approccio al 100%.

+0

Domanda: perché si fa a fare distinzione tra iOS 8 e iOS 7, dopo tutto? Non potresti semplicemente impostare sia timeoutIntervalForRequest che timeoutInterval? – dlinsin

6

Impossibile arrestare me, qui è la vostra risposta un po 'riscritta :)

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

Molto bello e facile da leggere, grazie! Sebbene il mio snippet di codice sia effettivamente distribuito su due classi distinte, ma applicherò ciò che posso da esso :) –

3

Dal iOS 8, il NSUrlSession in modalità background non significa chiamare questo metodo delegato se il server non risponde. -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error Il download/caricamento rimane inattivo a tempo indeterminato. Questo delegato viene chiamato su iOS7 con un errore quando il server non risponde.

In generale, una sessione in background NSURLSession non fallisce un'attività se qualcosa va storto sul filo. Piuttosto, continua a cercare il momento giusto per eseguire la richiesta e riprova in quel momento. Questo continua fino alla scadenza del timeout della risorsa (ovvero, il valore della proprietà timeoutIntervalForResource nell'oggetto NSURLSessionConfiguration che si utilizza per creare la sessione). L'impostazione predefinita per quel valore è una settimana! In altre parole, il comportamento di non riuscire per un timeout in iOS7 era errato. Nel contesto di una sessione in background, è più interessante non fallire immediatamente a causa di problemi di rete. Quindi, dal momento che iOS8, l'attività NSURLSession continua anche se incontra timeout e perdita di rete. Continua tuttavia fino al raggiungimento di timeoutIntervalForResource.

Quindi fondamentalmente timeoutIntervalForRequest non funzionerà nella sessione in background ma timeoutIntervalForResource lo farà.

Fonte: Apple Forum