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 sử dụng ngày càng tăng khi tập tin được tải
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
Tôi sẽ bắt đầu với tài liệu NSURLSession. – Andy
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