在我的应用程序中,我试图下载数千个图像(每个图像大小最大为3mb)和10个视频(每个视频大小最大为100mb),并将其保存在文档目录中。
为了实现这一点,我正在使用AFNetworking
在这里,我的问题是,当我使用慢速无线网络(约4mbps)时,我成功地获取了所有数据,但如果我在速度为100mbps的无线网络下进行下载,应用程序在下载图像时会收到内存警告,在下载视频时会出现内存压力问题,然后应用程序崩溃。
-(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];
}
以上代码我正在根据我必须下载的视频和图像的数量进行循环
这种行为背后的原因是什么
我甚至有两种场景的内存分配屏幕截图
请帮助
添加保存下载图像的代码也是
-(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
,它应该将内容直接流式传输到该文件,例如
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";
我认为,与使用持久存储将结果直接流式传输到outputStream
相比,这在内存使用方面没有那么重要,但我发现这是在启动许多并发请求时管理系统资源的另一种机制。
您可以开始使用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)
}];