【问题标题】:How to download a large file with the iPhone SDK and avoid memory usage issues?如何使用 iPhone SDK 下载大文件并避免内存使用问题?
【发布时间】:2010-10-12 01:04:16
【问题描述】:

我正在使用 NSURLConnection 类在我的 iPhone 应用程序中下载一个大文件,但它经常崩溃,因为它使用了太多内存。我正在使用通常的NSURLConnection 用法,将接收到的数据附加到NSMutableData 对象。

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.fileData appendData:data];
}

然后在我完成整个文件的下载后,我将它保存到本地临时文件中,并将其作为映射文件读取,如下所示:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    // save the downloaded data into a temporary file
    NSString *tempPath = NSTemporaryDirectory();
    NSString *tempFile = [tempPath stringByAppendingPathComponent:@"temp.pdf"];
    [self.fileData writeToFile:tempFile atomically:YES];
    NSData *mappedData = [NSData dataWithContentsOfMappedFile:tempFile];

    NSURL *baseURL = [NSURL URLWithString:@"http://mydomain.com"];
    [webView loadData:mappedData MIMEType:@"application/pdf" textEncodingName:@"UTF-8" baseURL:baseURL];
}

我可以在这里改进什么来避免这些内存使用问题?

【问题讨论】:

  • 我为此编写了一个库,我把它放在这里希望它对某些人有用,或者激励他们编写自己的解决方案。如果你没问题,当然可以。 github.com/thibaultCha/TCBlobDownload

标签: iphone memory-management nsurlconnection


【解决方案1】:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response {

    filename = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:save_name]; // filename is in .h file

    [[NSFileManager defaultManager] createFileAtPath:filename contents:nil attributes:nil];
        file =
[[NSFileHandle fileHandleForUpdatingAtPath:filename] retain];// file is in .h 

//if (file)     {
//
//      [file seekToEndOfFile];
//  }
 }

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSD
ata *)data {

 if (file)  { 

        [file seekToEndOfFile];

    } [file writeData:data]; 

}

- (void)connectionDidFinishLoading:(NSURLConnection*)connection { 

[file closeFile]; 

}

【讨论】:

  • 使用下面 Mobihunterz 发布的更简单的 didReceiveData() 是否有缺点?看起来简单干净。
  • DRFENCE didReceiveData() 很好,但每次调用此函数时它都会打开和关闭特定文件“file1”。并且在下载较大的文件时会多次调用该函数。因此,由于每次打开/关闭的开销,执行可能会有点慢。而上面的函数只是在这个方法中写入文件,只在开始和结束时打开和关闭文件。
  • 连接中的 seekToEndOfFile 不是:didReceiveData: 没必要吗? writeData:文档说If the receiver is a file, writing takes place at the file pointer’s current position. After it writes the data, the method advances the file pointer by the number of bytes written.
  • @Linus 感谢您的标记,但我没有检查它是否删除了这些东西。
【解决方案2】:

我正在使用

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    filename = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:save_name];
    NSFileHandle *file1 = [NSFileHandle fileHandleForUpdatingAtPath: filename];
    [file1 writeData: data];
    [file1 closeFile];
}

【讨论】:

    【解决方案3】:

    如果它那么大,为什么不将其写入文件,而不是将其保存在 NSData 对象中?

    【讨论】:

    • jpm:你会想看看 NSFileHandle 类。
    • 本,你是完全正确的。使用NSFileHandle 重写了我的课程以避免将整个文件保存在内存中,并且现在似乎工作得更好。也感谢丹尼尔的提示!
    猜你喜欢
    • 2011-06-13
    • 2011-03-20
    • 2011-04-29
    • 1970-01-01
    • 2013-05-01
    • 2011-04-29
    • 2015-09-05
    • 2012-03-14
    • 1970-01-01
    相关资源
    最近更新 更多