2009-03-08 11 views
21

Tôi đang sử dụng lớp NSURLConnection để tải xuống một tệp lớn trong ứng dụng iPhone của mình, nhưng nó thường xuyên gặp sự cố do sử dụng quá nhiều bộ nhớ. Tôi đang sử dụng cách sử dụng thông thường NSURLConnection, để thêm dữ liệu đã nhận vào đối tượng NSMutableData.Làm thế nào để tải xuống một tệp lớn với SDK iPhone và tránh các vấn đề về sử dụng bộ nhớ?

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

Sau đó, sau khi tôi hoàn thành tải về toàn bộ tập tin, tôi lưu nó vào một tập tin tạm thời của địa phương, và đọc nó như là một tập tin ánh xạ như thế này:

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

tôi có thể cải thiện gì ở đây để tránh những vấn đề sử dụng bộ nhớ?

+1

Tôi đã viết một thư viện cho rằng, tôi đặt nó ở đây hy vọng nó sẽ hữu ích cho một số người, hoặc truyền cảm hứng cho họ viết giải pháp riêng của họ. Nếu bạn là ok với nó tất nhiên. https://github.com/thibaultCha/TCBlobTải xuống – thibaultcha

Trả lời

17

Nếu nó lớn, tại sao không ghi nó vào tập tin như nó đi vào, thay vì giữ nó trong một đối tượng NSData?

+1

jpm: bạn sẽ muốn xem lớp NSFileHandle. –

+0

Ben, bạn hoàn toàn đúng. Viết lại lớp của tôi bằng cách sử dụng 'NSFileHandle' để tránh giữ toàn bộ tập tin trong bộ nhớ, và dường như làm việc tốt hơn bây giờ. Cảm ơn Daniel cho tip quá! – jpm

6

Tôi đang sử dụng

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

} 
+1

Làm việc của nó như một sự quyến rũ nhờ – objectivecdeveloper

+0

Có những hạn chế để sử dụng didReceiveData đơn giản hơn() dưới đây được đăng bởi Mobihunterz? Có vẻ đơn giản và sạch sẽ. – drfence

+0

DRFENCE didReceiveData() là tốt nhưng nó mở và đóng tệp cụ thể 'file1' mỗi khi hàm này được gọi. Và chức năng sẽ được gọi nhiều lần trong khi tải xuống các tệp lớn hơn. Vì vậy, việc thực hiện có thể hơi chậm do chi phí mở/đóng mỗi lần. Trong khi hàm trên chỉ ghi vào tệp trong phương thức này và mở và đóng tệp chỉ ở đầu và cuối. –