tldr: ImagedNamed ist in Ordnung. Es geht gut mit dem Gedächtnis um. Verwenden Sie es und hören Sie auf, sich Sorgen zu machen.
Edit Nov 2012 : Beachten Sie, dass diese Frage von iOS 2.0 stammt! Die Bildanforderungen und die Handhabung haben sich seitdem stark weiterentwickelt. Die Netzhaut vergrößert Bilder und lädt sie etwas komplexer. Mit der integrierten Unterstützung für iPad- und Retina-Bilder sollten Sie ImageNamed auf jeden Fall in Ihrem Code verwenden. Nun, der Nachwelt zuliebe:
Der Schwester-Thread in den Apple Dev-Foren erhielt etwas besseren Traffic. Insbesondere Rincewind fügte einige Autorität hinzu.
In iPhone OS 2.x gibt es Probleme, bei denen der imageNamed: -Cache auch nach einer Speicherwarnung nicht gelöscht wird. Zur gleichen Zeit + imageNamed: wurde nicht für den Cache, sondern für die Bequemlichkeit viel genutzt, was das Problem wahrscheinlich mehr vergrößert hat, als es hätte sein sollen.
während ich das warne
An der Geschwindigkeitsfront gibt es ein allgemeines Missverständnis darüber, was los ist. Das Größte, was + imageNamed: bewirkt, ist das Dekodieren der Bilddaten aus der Quelldatei, wodurch die Datengröße fast immer erheblich erhöht wird (z. B. verbraucht eine PNG-Datei in Bildschirmgröße beim Komprimieren möglicherweise einige Dutzend KB, verbraucht jedoch mehr als ein halbes MB dekomprimiert - Breite * Höhe * 4). Im Gegensatz dazu + imageWithContentsOfFile: Dekomprimiert dieses Bild jedes Mal, wenn die Bilddaten benötigt werden. Wie Sie sich vorstellen können, haben Sie hier nichts gewonnen, wenn Sie die Bilddaten nur einmal benötigen, außer dass eine zwischengespeicherte Version des Bildes herumhängt und wahrscheinlich länger als nötig. Wenn Sie jedoch ein großes Bild haben, das Sie häufig neu zeichnen müssen, gibt es Alternativen, obwohl ich in erster Linie empfehlen würde, das Neuzeichnen dieses großen Bildes zu vermeiden :).
In Bezug auf das allgemeine Verhalten des Caches wird der Cache basierend auf dem Dateinamen erstellt (daher sollten zwei Instanzen von + imageNamed: mit demselben Namen zu Verweisen auf dieselben zwischengespeicherten Daten führen), und der Cache wächst dynamisch, wenn Sie weitere Bilder über anfordern + imageNamed:. Unter iPhone OS 2.xa verhindert ein Fehler, dass der Cache verkleinert wird, wenn eine Speicherwarnung empfangen wird.
und
Nach meinem Verständnis sollte der Cache + imageNamed: Speicherwarnungen unter iPhone OS 3.0 berücksichtigen. Testen Sie es, wenn Sie eine Chance bekommen, und melden Sie Fehler, wenn Sie feststellen, dass dies nicht der Fall ist.
Also, da hast du es. imageNamed: Zerschmettert nicht Ihre Fenster und ermordet Ihre Kinder nicht. Es ist ziemlich einfach, aber es ist ein Optimierungswerkzeug. Leider ist es schlecht benannt und es gibt kein Äquivalent, das so einfach zu bedienen ist - daher wird es von den Leuten überbeansprucht und ist verärgert, wenn es einfach seinen Job macht
Ich habe UIImage eine Kategorie hinzugefügt, um dies zu beheben:
// 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 enthielt auch Beispielcode, um Ihre eigene optimierte Version zu erstellen. Ich kann nicht sehen, dass es die Wartung wert ist, aber hier ist es der Vollständigkeit halber.
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);
Der Nachteil dieses Codes ist, dass das decodierte Bild mehr Speicher benötigt, das Rendern jedoch schneller ist.