2014-12-04 14 views
6

A causa del cliente non è possibile implementare solo pochi download nel suo server in poco tempo e backgroundDownloadTaks erano molto incoerenti quando ci sono tanti file (500-1000 download) Decido di utilizzare NSURLDownloadTask senza background NSURLSession.NSURLSessione downloadTask non rilasciando memoria

Funziona abbastanza bene con una grande quantità di file, ma c'è un inconveniente. L'utilizzo della memoria è in continua crescita fino a quando ricevo un avviso di memoria. Quando lo ottengo, annullo le attività in sospeso e NSURLCache libero, ma la memoria non viene rilasciata, quindi quando riprendi i download ricevi lo stesso avviso di memoria.

Non sto utilizzando cancelWithResumeData per l'annullamento delle attività.

Questo è il mio codice

- (void) startDownloadFiles:(NSMutableArray*)arrayFiles 
{ 
    if([[UIDevice currentDevice] isMultitaskingSupported]) 
    { 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

      if (!self.session) 
      { 
       NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; 
       sessionConfiguration.HTTPMaximumConnectionsPerHost = 5; 
       sessionConfiguration.timeoutIntervalForRequest = 0; 
       sessionConfiguration.timeoutIntervalForResource = 0; 
       sessionConfiguration.requestCachePolicy = NSURLCacheStorageNotAllowed; 

       self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration 
                  delegate:self 
                 delegateQueue:nil]; 

      } 

      //Resetting session 
      [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { 

       for (NSURLSessionTask *_task in downloadTasks) 
       { 
        [_task cancel]; 
       } 

       [self.session resetWithCompletionHandler:^{      
        for (id<FFDownloadFileProtocol> file in self.selectedCatalogProducto.downloadInfo.arrayFiles) 
        { 
         if (cancel) 
          break; //Do not create more taks       

         if (![file isDownloaded]) 
          [self startDownloadFile:file]; 

        }     
       }]; 

      }]; 

     }); 

    } 
} 


- (void) startDownloadFile:(id<FFDownloadFileProtocol>)file 
{ 
    if (![file isDownloading]) 
    { 
     if ([file taskIdentifier] == -1 
      && ! cancel) 
     { 
      NSURLSessionDownloadTask *task = [self.session downloadTaskWithURL:[file downloadSource]]; 

      if (task) 
      { 
       [file setDownloadTask:task]; 
       [file setTaskIdentifier:[file downloadTask].taskIdentifier]; 
       [[file downloadTask] resume]; 
      } 
      else 
      { 
       NSLog(@"Error creando tarea para descargar %@", [file downloadSource]); 
      } 
     } 
    } 
} 

#pragma mark - Auxiliar Methods 

-(id<FFDownloadFileProtocol>)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier 
{ 
    for (id<FFDownloadFileProtocol> file in self.selectedCatalogProducto.downloadInfo.arrayFiles) 
    { 
     if (file.taskIdentifier == taskIdentifier) { 
      return file; 
     } 
    } 

    return nil; 
} 

#pragma mark - NSURLSessionDownloadTaskDelegate 

- (void) URLSession:(NSURLSession *)session 
     downloadTask:(NSURLSessionDownloadTask *)downloadTask 
     didWriteData:(int64_t)bytesWritten 
    totalBytesWritten:(int64_t)totalBytesWritten 
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite 
{ 
    if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) { 
     NSLog(@"Unknown transfer size"); 
    } 
    else 
    { 
     // Locate the FileDownloadInfo object among all based on the taskIdentifier property of the task. 
     id<FFDownloadFileProtocol> file = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier]; 
     // Calculate the progress. 
     file.downloadProgress = (double)totalBytesWritten/(double)totalBytesExpectedToWrite; 
//  [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
//   NSLog("%@ ; %f", [file fileName], [file downloadProgress]); 
//  }]; 
    } 
} 

- (void)URLSession:(NSURLSession *)session 
     downloadTask:(NSURLSessionDownloadTask *)downloadTask 
didFinishDownloadingToURL:(NSURL *)location 
{ 
    id<FFDownloadFileProtocol> file = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier]; 

    if (file) 
    { 
     NSError *error; 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 

     NSURL *destinationURL = [[NSURL fileURLWithPath:tempPath] URLByAppendingPathComponent:[file fileName]]; 

     if ([fileManager fileExistsAtPath:[destinationURL path]]) { 

      NSError *delError = nil; 
      [fileManager removeItemAtURL:destinationURL error:nil]; 

      if (delError) 
      { 
       NSLog(@"Error borrando archivo temporal en %@", [destinationURL path]); 
      } 

     } 

     BOOL success = [fileManager copyItemAtURL:location 
              toURL:destinationURL 
              error:&error]; 

     if (success) { 

      // Change the flag values of the respective FileDownloadInfo object. 

      file.isDownloading = NO; 
      file.isDownloaded = YES; 

      // Set the initial value to the taskIdentifier property of the file object, 
      // so when the start button gets tapped again to start over the file download. 

     } 
     else 
     { 
      NSLog(@"Unable to copy temp file to %@ Error: %@", [destinationURL path], [error localizedDescription]); 
     } 

     if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) 
     { 
      indexFile++; 
      [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
       [self numFilesDownloaded:indexFile]; 
      }]; 
     } 
    } 
} 

- (void)URLSession:(NSURLSession *)session 
       task:(NSURLSessionTask *)task 
didCompleteWithError:(NSError *)error 
{ 
    id<FFDownloadFileProtocol> file = [self getFileDownloadInfoIndexWithTaskIdentifier:task.taskIdentifier]; 

    if (error != nil 
     && error.code != -999) 
    { 
     //No se ha producido error o se ha cancelado la tarea bajo demanda 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 

      NSLog(@"Download: %@. \n Downlonad completed with error: %@", [task.response.URL absoluteString], [error localizedDescription]); 

      if (!cancel) 
      { 
       NSString *alertBody = @"Se ha producido un error en la descarga, por favor reanúdela manualmente"; 

       if ([error.domain isEqualToString:@"NSPOSIXErrorDomain"] && (error.code == 1)) 
       { 
        alertBody = @"Se ha interrumpido la descarga debido a que su iPad está bloqueado por código. Por favor reanude la descarga manualmente y evite que el iPad se bloquee"; 
       } 

       // Show a local notification when all downloads are over. 
       UILocalNotification *localNotification = [[UILocalNotification alloc] init]; 
       localNotification.alertBody = alertBody; 
       [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification]; 

       [self errorDownloading:error.localizedDescription]; 
      } 
     }]; 

    } 
    else if (file) 
    { 
     NSLog(@"%@ download finished successfully.", [[file downloadSource] absoluteString]); 

     file.taskIdentifier = -1; 

     // In case there is any resume data stored in the file object, just make it nil. 
     file.taskResumeData = nil; 
     file.downloadTask = nil; 
    } 
    else if (cancel) 
    { 
     NSLog(@"Tarea cancelada"); 
    } 

    if (self.selectedCatalogProducto.downloadInfo.arrayFiles.count == indexFile 
     && !cancel) 
    { 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      if (!complete) 
      { 
       complete = YES; 
       [self downloadComplete]; 
      } 
     }]; 
    } 

    task = nil; 
} 

#pragma mark - Memory warning 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 

    if (_isDownloading) 
    { 
     [self storeCatalogProductInfo:self.selectedCatalogProducto andDownloadInfo:YES]; 
     [self stopDownloading]; 
    } 

    [[NSURLCache sharedURLCache] removeAllCachedResponses]; 
    [self.session.configuration.URLCache removeAllCachedResponses]; 
} 

E questi sono due istantanee di utilizzo della memoria

Memory usage increasing when files are downloading Utilizzo della memoria aumentare quando i file stanno scaricando

Download tasks are stopped but memory is not released attività di download vengono interrotti ma la memoria non è rilasciato

Perché non posso memoria di leasing?

Grazie per qualsiasi aiuto fornito

+0

Vorrei iniziare con la documentazione NSURLSession. – Andy

+0

Ho letto tutta la documentazione ma non dico nulla sulla memoria. Solo "Importante: l'oggetto della sessione mantiene un forte riferimento al delegato fino a quando l'app non invalida la sessione in modo esplicito. Se non si annulla la sessione, l'app perde memoria". L'ho fatto ma non viene rilasciata memoria – Rotten

risposta

1

È necessario chiamare il metodo invalidateAndCancel sull'istanza NSURLSession quando hai finito di usarlo, altrimenti si perderà la memoria.