2009-03-08 5 views
21

Sto utilizzando la classe NSURLConnection per scaricare un file di grandi dimensioni nell'applicazione iPhone, ma si blocca ogni tanto perché utilizza troppa memoria. Sto facendo il solito uso di NSURLConnection per aggiungere i dati ricevuti a un oggetto NSMutableData.Come scaricare un file di grandi dimensioni con l'iPhone SDK ed evitare problemi di utilizzo della memoria?

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

Poi dopo aver finito di scaricare l'intero file, ho salvarlo in un file temporaneo locale e leggerlo come un file mappato in questo modo:

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

Cosa posso migliorare qui per evitare questi problemi di utilizzo della memoria?

+1

Ho scritto una libreria per questo, sto mettendo qui sperando che sia utile per alcune persone, o ispirare loro a scrivere la propria soluzione. Se stai bene, ovviamente. https://github.com/thibaultCha/TCBlobDownload – thibaultcha

risposta

17

Se è così grande, perché non scriverlo nel file così come viene, piuttosto che conservarlo in un oggetto NSData?

+1

jpm: ti consigliamo di verificare la classe NSFileHandle. –

+0

Ben, hai perfettamente ragione. Riscrivi la mia classe usando 'NSFileHandle' per evitare di mantenere l'intero file in memoria e sembra che funzioni molto meglio ora. Grazie Daniele anche per il suggerimento! – jpm

6

sto usando

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

Funziona come un fascino grazie – objectivecdeveloper

+0

Ci sono degli svantaggi nell'usare il più semplice didReceiveData() qui sotto postato da Mobihunterz? Sembra semplice e pulito. – drfence

+0

DRFENCE il didReceiveData() è buono ma apre e chiude il file particolare 'file1' ogni volta che viene chiamata questa funzione. E la funzione verrà chiamata numerose volte durante il download di file più grandi. Pertanto, l'esecuzione potrebbe essere un po 'lenta a causa del sovraccarico di apertura/chiusura ogni volta. Mentre la funzione sopra riportata scrive sul file in questo metodo e apre e chiude il file solo all'inizio e alla fine. –