tldr: ImagedNamed est très bien. Il gère bien la mémoire. Utilisez-le et arrêtez de vous inquiéter.
Edit Nov 2012 : Notez que cette question date d'iOS 2.0! Les exigences et la gestion des images ont beaucoup évolué depuis. Retina agrandit les images et leur chargement un peu plus complexe. Avec la prise en charge intégrée des images iPad et Retina, vous devez certainement utiliser ImageNamed dans votre code. Maintenant, pour la postérité:
Le fil sœur sur les forums Apple Dev a reçu un meilleur trafic. Plus précisément, Rincevent a ajouté une certaine autorité.
Il y a des problèmes dans iPhone OS 2.x où le cache imageNamed: ne serait pas effacé, même après un avertissement de mémoire. Dans le même temps + imageNamed: a été beaucoup utilisé non pas pour le cache, mais pour la commodité, ce qui a probablement amplifié le problème plus qu'il n'aurait dû.
tout en avertissant que
Sur le front de la vitesse, il y a un malentendu général sur ce qui se passe. La plus grande chose que + imageNamed: fait est de décoder les données d'image du fichier source, ce qui gonfle presque toujours considérablement la taille des données (par exemple, un fichier PNG de la taille d'un écran peut consommer quelques dizaines de Ko lorsqu'il est compressé, mais consomme plus d'un demi-Mo décompressé - largeur * hauteur * 4). Par contraste + imageWithContentsOfFile: décompressera cette image à chaque fois que les données d'image sont nécessaires. Comme vous pouvez l'imaginer, si vous n'avez besoin des données d'image qu'une seule fois, vous n'avez rien gagné ici, sauf d'avoir une version mise en cache de l'image qui traîne, et probablement plus longtemps que vous n'en avez besoin. Cependant, si vous avez une grande image que vous devez souvent redessiner, il existe des alternatives, même si celle que je recommanderais principalement est d'éviter de redessiner cette grande image :).
En ce qui concerne le comportement général du cache, il fait du cache basé sur le nom de fichier (donc deux instances de + imageNamed: avec le même nom devraient entraîner des références aux mêmes données mises en cache) et le cache augmentera de manière dynamique à mesure que vous demanderez plus d'images via + imageNommé:. Sur iPhone OS 2.x, un bogue empêche la réduction du cache lorsqu'un avertissement de mémoire est reçu.
et
Je crois comprendre que le + imageNamed: cache doit respecter les avertissements de mémoire sur iPhone OS 3.0. Testez-le lorsque vous en avez l'occasion et signalez les bogues si vous constatez que ce n'est pas le cas.
Alors, voilà. imageNamed: ne brisera pas vos fenêtres ni ne tuera vos enfants C'est assez simple mais c'est un outil d'optimisation. Malheureusement, il est mal nommé et il n'y a pas d'équivalent qui soit aussi facile à utiliser - par conséquent, les gens en abusent et s'énervent quand il fait simplement son travail
J'ai ajouté une catégorie à UIImage pour résoudre ce problème:
// 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]];
}
Rincewind a également inclus un exemple de code pour créer votre propre version optimisée. Je ne vois pas que cela vaut la peine de le maintenir mais ici, c'est pour être complet.
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);
Le compromis avec ce code est que l'image décodée utilise plus de mémoire mais le rendu est plus rapide.