2009-03-08 13 views
21

Używam klasy NSURLConnection, aby pobrać duży plik w mojej aplikacji na iPhone'a, ale ulega awarii co jakiś czas, ponieważ używa zbyt dużo pamięci. Używam zwykłego użycia NSURLConnection, aby dołączyć odebrane dane do obiektu NSMutableData.Jak pobrać duży plik za pomocą zestawu iPhone SDK i uniknąć problemów z używaniem pamięci?

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

Następnie po skończeniu pobierania całego pliku, zapisać go do lokalnego pliku tymczasowego i odczytać go jako odwzorowanym pliku jak poniżej:

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

Co mogę poprawić, żeby uniknąć tych problemy z używaniem pamięci?

+1

pisałem bibliotekę do tego, Kładę go tutaj w nadziei, że będzie użyteczny dla niektórych ludzi, lub zainspirować je pisać własne rozwiązanie. Jeśli oczywiście nie masz nic przeciwko temu. https://github.com/thibaultCha/TCBlobDownload – thibaultcha

Odpowiedz

17

Jeśli jest taki duży, to dlaczego nie zapisać go do pliku, jak to przychodzi, zamiast przechowywać go w obiekcie NSData?

+1

jpm: będziesz chciał sprawdzić klasę NSFileHandle. –

+0

Ben, masz całkowitą rację. Przepisz moją klasę za pomocą 'NSFileHandle', aby uniknąć przechowywania całego pliku w pamięci i wygląda na to, że działa teraz lepiej. Dziękuję również Danielowi za podpowiedź! – jpm

6

używam

- (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

Działa jak wdzięk dzięki – objectivecdeveloper

+0

Czy są wady używania prostszej metody didReceiveData() opisanej poniżej przez Mobihunterz? Wydaje się proste i czyste. – drfence

+0

DRFENCE the didReceiveData() jest dobre, ale otwiera i zamyka określony plik 'plik1' za każdym razem, gdy wywoływana jest ta funkcja. Funkcja będzie wywoływana wiele razy podczas pobierania większych plików. Tak więc wykonanie może być nieco powolne z powodu narzutów otwierania/zamykania za każdym razem. Chociaż powyższa funkcja po prostu zapisuje do pliku w tej metodzie i otwiera i zamyka plik tylko na początku i na końcu. –

Powiązane problemy