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

时间:2014-10-22 14:44:23

标签: ios objective-c afnetworking memory-pressure

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

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

这里我的问题是当我使用慢速wifi(大约4mbps)时,我成功获取所有数据,但如果我在 wifi下进行同样的下载速度为100mbps 应用程序在下载视频时下载图像和内存压力问题时出现内存警告,然后应用程序崩溃 。< / p>

-(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.");
    }
}

2 个答案:

答案 0 :(得分:1)

这种行为的原因是你正在将大文件加载到内存中(并且可能发生的速度很快,以至于你的应用程序没有机会响应内存压力通知)。

您可以通过不将这些下载内容加载到内存中来控制峰值内存使用量来缓解这个问题。下载大文件时,通常最好将它们直接传输到持久存储。要使用AFNetworking执行此操作,您可以设置outputStream的{​​{1}},它应该将内容直接流式传输到该文件,例如

AFURLConnectionOperation

顺便说一句,你会注意到我不只是在这些请求上调用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"; ,但我发现这是在启动许多并发请求时管理系统资源的另一种机制。

答案 1 :(得分:0)

您可以开始使用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)
     }];