2014-12-04 16 views
6

Do khách hàng không thể thực hiện một số tải xuống trong máy chủ của mình trong một thời gian ngắn và backgroundDownloadTaks rất không nhất quán khi có quá nhiều tệp (500-1000 lượt tải xuống) tôi quyết định sử dụng NSURLDownloadTask không có nền NSURLSession.NSURLSession downloadTask không giải phóng bộ nhớ

Nó hoạt động khá tốt với một lượng lớn tệp, nhưng có một sự bất tiện. Sử dụng bộ nhớ luôn phát triển cho đến khi tôi nhận được cảnh báo bộ nhớ. Khi tôi nhận được nó tôi hủy bỏ các nhiệm vụ đang chờ xử lý và NSURLCache miễn phí nhưng bộ nhớ không được phát hành vì vậy khi bạn tiếp tục tải xuống, bạn sẽ nhận được cảnh báo bộ nhớ tương tự.

Tôi không sử dụng cancelWithResumeData để hủy các tác vụ.

Đây là mã của tôi

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

Và đây là hai bản chụp của việc sử dụng bộ nhớ

Memory usage increasing when files are downloading Memory sử dụng ngày càng tăng khi tập tin được tải

Download tasks are stopped but memory is not released Tải về nhiệm vụ được dừng lại nhưng ký ức không phải là đã phát hành

Tại sao tôi không thể quay lại thuê bộ nhớ?

Nhờ sự giúp đỡ cung cấp

+0

Tôi sẽ bắt đầu với tài liệu NSURLSession. – Andy

+0

Tôi đã đọc toàn bộ tài liệu nhưng không nói gì về bộ nhớ. Chỉ có "Quan trọng: Đối tượng phiên giữ một tham chiếu mạnh mẽ đến đại biểu cho đến khi ứng dụng của bạn vô hiệu hóa phiên. Nếu bạn không làm mất hiệu lực phiên, ứng dụng của bạn sẽ rò rỉ bộ nhớ". Tôi đã làm nó nhưng không có bộ nhớ nào được phát hành – Rotten

Trả lời

1

Bạn cần phải gọi phương thức invalidateAndCancel trên dụ NSURLSession của bạn khi bạn sử dụng xong, nếu không nó sẽ bị rò rỉ bộ nhớ.

Các vấn đề liên quan