gpt4 book ai didi

objective-c - NSURLSession downloadTask 不释放内存

转载 作者:太空狗 更新时间:2023-10-30 03:45:10 25 4
gpt4 key购买 nike

由于客户无法在短时间内在他的服务器上实现少量下载,并且当有这么多文件(500-1000 下载)时,backgroundDownloadTaks 非常不一致,我决定使用没有后台 NSURLSession 的 NSURLDownloadTask。

它适用于大量文件,但有一个不便之处。内存使用量一直在增长,直到我收到内存警告。当我得到它时,我取消了挂起的任务并释放了 NSURLCache,但是内存没有被释放,所以当你恢复下载时,你会得到同样的内存警告。

我没有使用 cancelWithResumeData 来取消任务。

这是我的代码

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

这是两个内存使用快照

Memory usage increasing when files are downloading下载文件时内存使用量增加

Download tasks are stopped but memory is not released下载任务停止但内存未释放

为什么我不能释放内存?

感谢您提供的任何帮助

最佳答案

您需要在使用完 NSURLSession 实例后调用 invalidateAndCancel 方法,否则会泄漏内存。

关于objective-c - NSURLSession downloadTask 不释放内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27300415/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com