使用AFNetworking下载多个文件时的内存压力问题

在我的应用程序中,我试图下载数以千计的图像(每个图像大小最多3mb)和10个video(每个video大小最大为100mb),并将其保存在文档目录中。

为了实现这一点,我正在使用AFNetworking

在这里,我的问题是, 当我使用一个慢的wifi(约4mbps)成功所有的数据,但同样的下载,如果我正在下一个100mbps速度与WiFi应用程序正在下载图像和内存下载video时压力问题,然后应用程序崩溃

-(void) AddVideoIntoDocument :(NSString *)name :(NSString *)urlAddress{ NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlAddress]]; [theRequest setTimeoutInterval:1000.0]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:theRequest]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:name]; operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"Successfully downloaded file to %@", path); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Error: %@", error); }]; [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) { //NSLog(@"Download = %f", (float)totalBytesRead / totalBytesExpectedToRead); }]; [operation start]; } -(void)downloadRequestedImage : (NSString *)imageURL :(NSInteger) type :(NSString *)imgName{ NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:imageURL]]; [theRequest setTimeoutInterval:10000.0]; AFHTTPRequestOperation *posterOperation = [[AFHTTPRequestOperation alloc] initWithRequest:theRequest]; posterOperation.responseSerializer = [AFImageResponseSerializer serializer]; [posterOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { //NSLog(@"Response: %@", responseObject); UIImage *secImg = responseObject; if(type == 1) { // Delete the image from DB [self removeImage:imgName]; } [self AddImageIntoDocument:secImg :imgName]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"Image request failed with error: %@", error); }]; [posterOperation start]; } 

上面的代码,我根据我必须下载的video和图像的数量循环

这种行为背后的原因是什么?

我甚至有两个场景的内存分配屏幕截图

请帮忙

添加代码以保存下载的图像

 -(void)AddImageIntoDocument :(UIImage *)img :(NSString *)str{ if(img) { NSData *pngData = UIImageJPEGRepresentation(img, 0.4); NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *filePathName =[[paths objectAtIndex:0]stringByAppendingPathComponent:str]; [pngData writeToFile:filePathName atomically:YES]; } else { NSLog(@"Network Error while downloading the image!!! Please try again."); } } 

这种行为的原因是,你正在加载你的大文件到内存中(据推测,这很快发生,你的应用程序没有机会回应内存压力通知)。

您可以通过不将这些下载内容加载到内存中来控制峰值内存使用情况,从而减轻这一负担 下载大文件时,通常最好将它们直接传输到持久性存储器。 要做到这一点与AFNetworking,你可以设置AFURLConnectionOperation的outputStream ,它应该直接stream内容到该文件,例如

 AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; NSString *path = [documentsPath stringByAppendingPathComponent:[url lastPathComponent]]; // use whatever path is appropriate for your app operation.outputStream = [[NSOutputStream alloc] initToFileAtPath:path append:NO]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { NSLog(@"successful"); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"failure: %@", error); }]; [self.downloadQueue addOperation:operation]; 

顺便说一句,你会注意到,我不只是调用这些请求start 。 就个人而言,我总是将它们添加到我已经指定了最大并发操作数的队列中:

 self.downloadQueue = [[NSOperationQueue alloc] init]; self.downloadQueue.maxConcurrentOperationCount = 4; self.downloadQueue.name = @"com.domain.app.downloadQueue"; 

我认为这不是关于内存使用情况,而是使用持久性存储将结果直接stream式传输到outputStream ,但是我发现这是另一种在启动多个并发请求时pipe理系统资源的机制。

你可以开始使用NSURLSession的downloadTask。

我认为这将解决您的问题。

 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://someSite.com/somefile.zip"]]; [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { // Use location (it's file URL in your system) }]; 
Interesting Posts