tldr: ImagedNamed va bene. Gestisce bene la memoria. Usalo e smetti di preoccuparti.
Modifica novembre 2012 : nota che questa domanda risale a iOS 2.0! Da allora, i requisiti e la gestione delle immagini sono cambiati molto. Retina rende le immagini più grandi e caricandole leggermente più complesse. Con il supporto integrato per iPad e immagini retina, dovresti sicuramente usare ImageNamed nel tuo codice. Ora, per il bene dei posteri:
Il thread gemello sui forum di sviluppo di Apple ha ricevuto un traffico migliore. Nello specifico Scuotivento ha aggiunto una certa autorità.
Ci sono problemi in iPhone OS 2.x in cui la cache imageNamed: non verrebbe cancellata, anche dopo un avviso di memoria. Allo stesso tempo + imageNamed: è stato utilizzato molto non per la cache, ma per comodità, che probabilmente ha ingrandito il problema più di quanto avrebbe dovuto essere.
pur avvertendolo
Sul fronte della velocità, c'è un malinteso generale su ciò che sta accadendo. La cosa più importante che fa + imageNamed: è decodificare i dati dell'immagine dal file sorgente, che quasi sempre aumenta significativamente la dimensione dei dati (ad esempio, un file PNG di dimensioni dello schermo potrebbe consumare alcune dozzine di KB quando viene compresso, ma consuma più di mezzo MB decompresso - larghezza * altezza * 4). Al contrario + imageWithContentsOfFile: decomprimerà quell'immagine ogni volta che sono necessari i dati dell'immagine. Come puoi immaginare, se hai bisogno dei dati dell'immagine solo una volta, non hai vinto nulla qui, tranne per avere una versione memorizzata nella cache dell'immagine in giro, e probabilmente più a lungo del necessario. Tuttavia, se hai un'immagine di grandi dimensioni che devi ridisegnare spesso, allora ci sono alternative, anche se quella che consiglierei principalmente è evitare di ridisegnare quell'immagine grande :).
Per quanto riguarda il comportamento generale della cache, esegue la cache in base al nome del file (quindi due istanze di + imageNamed: con lo stesso nome dovrebbero risultare riferimenti agli stessi dati memorizzati nella cache) e la cache crescerà dinamicamente man mano che si richiedono più immagini tramite + imageNamed :. Su iPhone OS 2.xa un bug impedisce che la cache venga ridotta quando viene ricevuto un avviso di memoria.
e
La mia comprensione è che + imageNamed: cache dovrebbe rispettare gli avvisi di memoria su iPhone OS 3.0. Provalo quando ne hai la possibilità e segnala i bug se trovi che non è così.
Così il gioco è fatto. imageNamed: non romperà le finestre né ucciderà i tuoi figli. È piuttosto semplice ma è uno strumento di ottimizzazione. Purtroppo ha un nome sbagliato e non esiste un equivalente che sia così facile da usare, quindi le persone lo abusano e si arrabbiano quando semplicemente fa il suo lavoro
Ho aggiunto una categoria a UIImage per risolvere il problema:
// header omitted
// Before you waste time editing this, please remember that a semi colon at the end of a method definition is valid and a matter of style.
+ (UIImage*)imageFromMainBundleFile:(NSString*)aFileName; {
NSString* bundlePath = [[NSBundle mainBundle] bundlePath];
return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@", bundlePath,aFileName]];
}
Scuotivento ha incluso anche un codice di esempio per creare la tua versione ottimizzata. Non vedo che valga la pena, ma qui è per completezza.
CGImageRef originalImage = uiImage.CGImage;
CFDataRef imageData = CGDataProviderCopyData(
CGImageGetDataProvider(originalImage));
CGDataProviderRef imageDataProvider = CGDataProviderCreateWithCFData(imageData);
CFRelease(imageData);
CGImageRef image = CGImageCreate(
CGImageGetWidth(originalImage),
CGImageGetHeight(originalImage),
CGImageGetBitsPerComponent(originalImage),
CGImageGetBitsPerPixel(originalImage),
CGImageGetBytesPerRow(originalImage),
CGImageGetColorSpace(originalImage),
CGImageGetBitmapInfo(originalImage),
imageDataProvider,
CGImageGetDecode(originalImage),
CGImageGetShouldInterpolate(originalImage),
CGImageGetRenderingIntent(originalImage));
CGDataProviderRelease(imageDataProvider);
UIImage *decompressedImage = [UIImage imageWithCGImage:image];
CGImageRelease(image);
Il compromesso con questo codice è che l'immagine decodificata utilizza più memoria ma il rendering è più veloce.