2014-12-04 17 views
6

Ponieważ klient nie może zaimplementować tylko kilku pobrań na swoim serwerze w krótkim czasie, a backgroundDownloadTaks były bardzo niespójne, gdy jest tak dużo plików (500-1000 pobrań) Decyduję się użyć NSURLDownloadTask bez tła NSURLSession.NSURLSession downloadTask nie zwalnia pamięci

Działa całkiem dobrze z dużą ilością plików, ale jest niedogodność. Wykorzystanie pamięci stale wzrasta, dopóki nie otrzymam ostrzeżenia o pamięci. Kiedy go otrzymam, anuluję oczekujące zadania i uwolnię NSURLCache, ale pamięć nie zostanie zwolniona, więc po wznowieniu pobierania otrzymasz takie samo ostrzeżenie o pamięci.

Nie używam cancelWithResumeData do anulowania zadań.

To jest mój kod

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

I to są dwa migawka zużycie pamięci

Memory usage increasing when files are downloading Użycie pamięci wzrasta, gdy pliki pobierasz

Download tasks are stopped but memory is not released zadań pobierania są zatrzymane, ale pamięć nie jest wydany

Dlaczego nie mogę ponownie dzierżawa pamięci?

Dzięki za wszelką pomoc pod warunkiem

+0

Zacznę od dokumentacji NSURLSession. – Andy

+0

Przeczytałem całą dokumentację, ale nie mówię nic o pamięci. Tylko że "Ważne: Obiekt sesji zachowuje silne odniesienie do delegata, dopóki aplikacja jawnie nie anuluje sesji. Jeśli sesja nie zostanie unieważniona, aplikacja wycieknie z pamięci." Zrobiłem to, ale pamięć nie została zwolniona – Rotten

Odpowiedz

1

Trzeba wywołać metodę invalidateAndCancel na przykład NSURLSession kiedy skończysz go używać, w przeciwnym razie spowoduje to wyciek pamięci.

Powiązane problemy