tldr : ImagedNamed est bien. Il gère bien la mémoire. Utilisez-le et arrêtez de vous inquiéter.
Edition Nov 2012 : Notez que cette question date d'iOS 2.0 ! Les exigences et le traitement des images ont beaucoup évolué depuis. La technologie Retina rend les images plus grandes et leur chargement légèrement plus complexe. Avec la prise en charge intégrée de l'iPad et des images rétina, vous devriez certainement utiliser ImageNamed dans votre code. Maintenant, pour la postérité :
El fil conducteur sur les forums de développement d'Apple a reçu un meilleur trafic. Plus précisément Rincewind 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. En même temps, +imageNamed : a été beaucoup utilisé, non pas pour le cache, mais pour sa commodité, ce qui a probablement amplifié le problème plus qu'il n'aurait dû l'être.
tout en avertissant que
Sur le front de la vitesse, il y a une incompréhension générale de ce qui se passe. La plus grande chose que +imageNamed : fait est de décoder les données de l'image à partir du fichier source, ce qui gonfle presque toujours de manière significative la taille des données (par exemple, un fichier PNG de taille écran peut consommer quelques dizaines de Ko lorsqu'il est compressé, mais consomme plus d'un demi-moteur décompressé - largeur * hauteur * 4). En revanche, +imageWithContentsOfFile : décompressera cette image chaque fois que les données de l'image seront nécessaires. Comme vous pouvez l'imaginer, si vous n'avez besoin des données de l'image qu'une seule fois, vous n'avez rien gagné ici, si ce n'est d'avoir une version en cache de l'image qui traîne, et probablement plus longtemps que ce dont vous avez besoin. Cependant, si vous avez une grande image que vous devez redessiner souvent, alors il y a des alternatives, bien que celle que je recommanderais principalement soit d'éviter de redessiner cette grande image :).
En ce qui concerne le comportement général du cache, il est basé sur le nom de fichier (ainsi, deux instances de +imageNamed : avec le même nom devraient donner lieu à des références aux mêmes données mises en cache) et le cache s'agrandit dynamiquement au fur et à mesure que vous demandez d'autres images via +imageNamed :. Sur l'iPhone OS 2.x, un bogue empêche le cache d'être réduit lorsqu'un avertissement de mémoire est reçu.
et
D'après ce que j'ai compris, le +imageNamed : cache devrait respecter les avertissements de mémoire sur iPhone OS 3.0. Testez-le quand vous en aurez l'occasion et signalez les bogues si vous constatez que ce n'est pas le cas.
Donc, vous l'avez. imageNamed : ne va pas briser votre Windows ou assassiner vos enfants. C'est assez simple mais c'est un outil d'optimisation. Malheureusement, son nom est mal choisi et il n'existe pas d'équivalent aussi facile à utiliser - c'est pourquoi les gens en abusent et s'énervent lorsqu'il fait simplement son travail.
J'ai ajouté une catégorie à UIImage pour corriger cela :
// 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 quelques exemples de code pour construire votre propre version optimisée. Je ne pense pas que cela vaille la peine de le maintenir, mais le voici 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 que le rendu est plus rapide.