Differenza tra e ?

Voglio caricare alcune immagini nella mia applicazione dal file system. Ci sono 2 semplici modi per farlo:

[UIImage imageNamed:fullFileName] 

o:

 NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension]; NSData *imageData = [NSData dataWithContentsOfFile:fileLocation]; [UIImage imageWithData:imageData]; 

Preferisco il primo perché è molto meno codice, ma ho visto alcune persone dire che l’immagine è memorizzata nella cache e che questo metodo utilizza più memoria? Dato che non mi fido delle persone sulla maggior parte degli altri forum, ho pensato di porre la domanda qui, c’è qualche differenza pratica, e in tal caso quale è “migliore”?

Ho provato a profilare la mia app utilizzando lo strumento Object Allocation e non vedo alcuna differenza pratica, anche se ho provato solo nel simulatore e non su un iPhone stesso.

Dipende da cosa stai facendo con l’immagine. Il metodo imageNamed: memorizza l’immagine nella cache, ma in molti casi aiuta l’utilizzo della memoria. Ad esempio, se caricate un’immagine 10 volte per visualizzarla insieme ad un testo in una vista tabella, UIImage manterrà una sola rappresentazione di quell’immagine nella memoria invece di allocare 10 oggetti separati. D’altra parte, se hai un’immagine molto grande e non la stai riutilizzando, potresti caricare l’immagine da un object dati per assicurarti che sia stata rimossa dalla memoria quando hai finito.

Se non hai immagini enormi, non me ne preoccuperei. A meno che tu non veda un problema (e dei complimenti per il controllo dell’allocazione dell’object invece dell’ottimizzazione preventiva), sceglierei meno righe di codice su miglioramenti di memoria trascurabili.

Nella mia esperienza [UIImage imageNamed:] ha prestazioni decisamente migliori, soprattutto se utilizzato in UITableViews .

Non è solo la memoria, ma anche la decodifica image . Averlo memorizzato nella cache è molto più veloce.

Come dice il riferimento API di UIImage :

+ (UIImage *) imageNamed: nome (NSString *)

Questo metodo cerca nelle cache di sistema per un object immagine con il nome specificato e restituisce quell’object se esiste. Se un object immagine corrispondente non è già presente nella cache, questo metodo carica i dati dell’immagine dal file specificato, li memorizza nella cache e quindi restituisce l’object risultante.

+ (UIImage *) imageWithContentsOfFile: (NSString *) percorso

Questo metodo non memorizza nella cache l’object immagine.

così, possiamo vedere che se hai molti stessi elementi dell’interfaccia utente (come UITableViewCell) che possono usare la stessa immagine (spesso come icone ), e a causa delle prestazioni, ovviamente vogliamo riutilizzare la stessa immagine , in modo da salverà parte della memoria per altri usi. Generalmente l’ immagine riutilizzata viene spesso utilizzata nell’elemento ui che il nostro utente può utilizzare su di esso molte volte . Quindi è importante che riutilizziamo. Così puoi scegliere di utilizzare il metodo imageNamed .

D’altra parte, in un’applicazione, ci sarà qualche elemento dell’interfaccia che sarà presente durante il ciclo di vita dell’app, come un pulsante, una vista logo, quindi queste immagini utilizzate da questi elementi dell’interfaccia utente potrebbero essere presenti anche durante l’app ciclo di vita, non si dovrebbe considerare se questa immagine dovrebbe essere cache o no. Così si può scegliere di utilizzare il metodo imageNamed .


Al contrario, in un’applicazione, ci sono spesso elementi dell’interfaccia utente creati in modo dinamico. Ad esempio, la nostra applicazione supporta lo sfondo dinamico, in modo che l’utente possa scegliere lo sfondo che preferisce. E lo sfondo potrebbe essere un’immagine. Così potremmo avere un’interfaccia che elenca un sacco di sfondi diversi (spesso mostrati con UIImageView ) che l’utente può scegliere , possiamo dare un nome alla vista elenco MyBackgroundListView . Così una volta che l’utente sceglie un’immagine di sfondo, MyBackgroundListView dovrebbe essere distrutto, perché ha finito la sua funzione. La prossima volta che l’utente vuole cambiare il suo background, possiamo creare nuovamente MyBackgroundListView . Pertanto, le immagini utilizzate da MyBackgroundListView non devono essere memorizzate nella cache o la memoria della nostra applicazione si esaurirà. Pertanto, è necessario utilizzare il metodo imageWithContentsOfFile .

Come dice il documento di Apple che supporta le schermate ad alta risoluzione nelle viste

Sui dispositivi con schermi ad alta risoluzione, imageNamed:, imageWithContentsOfFile :, e initWithContentsOfFile: i metodi cercano automaticamente una versione dell’immagine richiesta con il modificatore @ 2x nel suo nome. Se ne trova uno, carica invece quell’immagine. Se non si fornisce una versione ad alta risoluzione di una determinata immagine, l’object immagine carica ancora un’immagine a risoluzione standard (se esistente) e la ridimensiona durante il disegno.

quindi ti preoccupare del percorso di ricerca dell’immagine per il problema della retina. IOS ti aiuterà ad affrontarlo.

Scusa per il mio pessimo inglese . Potrebbe essere utile.

Se non vuoi che la tua immagine venga memorizzata nella cache, puoi anche utilizzare initWithContentsOfFile direttamente:

 NSString *fileLocation = [[NSBundle mainBundle] pathForResource:fileName ofType:extension]; UIImage* yourImage = [[[UIImage alloc] initWithContentsOfFile:imagePath] autorelease]; 

Mi è stato anche detto che [UIImage imageNamed:] fa un po ‘troppo caching e le immagini non vengono spesso rilasciate. Mi è stato detto di stare attento a usarlo.

imageWithData è utile quando si memorizza l’immagine binaria in un database o si scarica progressivamente un’immagine di grandi dimensioni dal Web.

Non utilizzerei imagenamed se la tua app ha un sacco di immagini grandi che non sono le stesse. Ho riscontrato un arresto anomalo dell’app a causa dell’utilizzo eccessivo.

Non credo che l’immagine venga memorizzata nella cache e non so perché lo stiate dicendo tutti. UIImage è una sottoclass di NSObject che utilizza i contatori di riferimento per tenere traccia delle cose a cui è correlato. Quindi quando carichi un’immagine, fa la stessa cosa. Se carichi la stessa immagine più volte, avrà (o dovrebbe) solo una copia dell’immagine in memoria e aumenterà il contatore di riferimento ogni volta che dovrai usare qualcosa con quell’immagine. Con i contatori di riferimento intendo che quando il conteggio arriva a 0, si cancella da solo. quindi “alloc”, “retain” sono ogni +1 al conteggio e “release” è -1. Non solo è un modo migliore per gestire la memoria, ma questo stile di programmazione aiuta anche a eliminare le perdite di memoria.