5

Ho implementato un'app di download manager per iOS 7+ utilizzando NSURLSession. Il download manager ha un elenco di file accodati da scaricare in ordine di priorità. Il download funziona correttamente mentre l'app è in background e le chiamate delegate vengono richiamate correttamente. Ma quando va applicazione in background, anche se il download viene completato ci vuole troppo tempo perDownload di un elenco di 100 file uno per uno utilizzando NSURLSession in background

NSURLSession delegate:- **URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL

ottenere chiamato. Alcune volte i delegati non vengono chiamati affatto e quando vengo in primo piano viene chiamato il delegato dell'attività di download. Qualche motivo per questo ritardo?

+0

Sono di fronte allo stesso problema. Sto passando una serie di elementi e il metodo di delega viene attivato solo quando rilancio l'app. –

+0

I callback sono incoerenti e i download impiegano troppo tempo per iniziare. Con piccoli file l'ho provato con il simulatore e ho scaricato alcuni piccoli file di immagine. I callback per il download completato si attivano dopo che i download sono stati completati 2 o 3 minuti fa. causa il ritardo per l'avvio del prossimo file da scaricare. Il problema si presenta quando porto la mia app in background. In primo piano le stesse funzioni funzionano bene. – Sulabh

+0

Segui tutte le istruzioni in https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW44 (Trasferimento in background considerazioni)? Voglio dire, usi la configurazione della sessione in background e implementi tutte le callback necessarie in appDelegate e NSURLSessionDelegate? – user2260054

risposta

0

Ho avuto un problema molto simile in cui l'attività in background si avviava ma poi sembrava in pausa. L'attività dovrebbe quindi essere completata quando l'applicazione ritorna in primo piano.

ho verificato che questo è stato il caso per registrare i dati trasmessi dal -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite

Ho trovato che il modo per aggirare questo problema è a che fare con il modo di archiviare, gestire ed eseguire i gestori di completamento.

Nel mio caso il processo inizia con

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{ 

[self.fmStore performBackgroundRefresh:^(UIBackgroundFetchResult result) { 

    //Set application badge if new data is available 
    if (result==UIBackgroundFetchResultNewData) [UIApplication sharedApplication].applicationIconBadgeNumber++; 
    completionHandler(result); 

}]; 
} 

in cui una notifica remota avvia il processo di download.

Il metodo che gestisce il download restituisce un valore dipendente dalla disponibilità di nuovi dati

-(void)performBackgroundRefresh:(void (^)(UIBackgroundFetchResult))completion{ 
    if(newData) completion(UIBackgroundFetchResultNewData); 
    else completion(UIBackgroundFetchResultNoData); 
} 

A questo punto si ritorna al ApplicationDelegate in cui il gestore di completamento viene memorizzato

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{ 
//Store completion handler for background session 
self.sessionCompletionHandler=completionHandler; 
} 

Infine , questo pezzo di codice viene eseguito che chiama il gestore di completamento e crea le notifiche appropriate

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{ 
[session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { 
    if (![downloadTasks count]) { 


     FM_AppDelegate *appDelegate=(FM_AppDelegate *)[[UIApplication sharedApplication] delegate]; 
     if (appDelegate.sessionCompletionHandler) { 
      void (^completionHandler)() = appDelegate.sessionCompletionHandler; 
      appDelegate.sessionCompletionHandler = nil; 
      completionHandler(); 
     } 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"ContentRefreshNotification" object:Nil]; 
     }]; 
    } 
}]; 
} 

Questo processo avanti e indietro si verifica nel mio caso poiché NSURLSession esiste in un oggetto che è una proprietà di ApplicationDelegate. Se si implementa NSURLSession come proprietà di ApplicationDelegate stesso, tutto questo codice esisterà nello stesso file.

Spero che questo aiuti, ma se avete bisogno di ulteriori informazioni si prega di vedere questi due tutorial 1 e 2 come il mio codice è basato su ciò che ho letto in questi.

+0

@Saddiq Jaffer Nel video NSURLSession in WWDC 2014 Apple consiglia di scaricare uno per uno e usa invece interi file. – Sulabh

+0

Questo è esattamente ciò che sto facendo nel metodo '- (void) performBackgroundRefresh: (void (^) (UIBackgroundFetchResult)) completion'. Il codice per il download non è mostrato nel mio esempio, mentre stavo solo cercando di dimostrare come gestire e chiamare i gestori di completamento. –