2009-05-29 6 views
116

Edit Februar 2014: Beachten Sie, dass diese Frage stammt aus iOS 2.0! Bildanforderungen und Handhabung haben sich seitdem stark weiterentwickelt. Retina macht Bilder größer und lädt sie etwas komplexer. Mit der integrierten Unterstützung für iPad und Retina Bilder, sollten Sie ImageNamed in Ihrem Code verwenden.Zerstreuung der UIImage BildNamed: FUD

Ich sehe eine Menge Leute sagen imageNamed ist schlecht, aber gleiche Anzahl von Leuten, die sagen, die Leistung ist gut - vor allem beim Rendern UITableView s. Siehe this SO question zum Beispiel oder this article auf iPhoneDeveloperTips.com

UIImage ‚s imageNamed Methode verwendet, um Leck so wurde es am besten vermieden werden, aber in der letzten Versionen behoben worden. Ich würde gerne den Caching-Algorithmus besser verstehen, um eine vernünftige Entscheidung darüber zu treffen, wo ich dem System vertrauen kann, um meine Bilder zu cachen und wo ich extra gehen muss und es selbst machen muss. Mein derzeitiges Grundverständnis ist, dass es sich um eine einfache NSMutableDictionary von UIImages handelt, auf die mit dem Dateinamen verwiesen wird. Es wird größer und wenn der Speicher ausgeht, wird es viel kleiner.

Zum Beispiel weiß jemand sicher, dass das Bild Cache hinter imageNamed nicht auf didReceiveMemoryWarning reagiert? Es scheint unwahrscheinlich, dass Apple das nicht tun würde.

Wenn Sie einen Einblick in den Caching-Algorithmus haben, schreiben Sie ihn hier.

+1

Ich bin in der Spannung. :) – Kriem

+2

ich auch. Scheint so, als ob SO nicht so voller Genies ist, wie ich dachte. –

+0

Scheint, als ob du etwas Zeit damit verbracht hast, dies zu untersuchen. Haben Sie irgendwelche Experimente durchgeführt, die negative Auswirkungen von UIImage imageNamed auf die neueste Version von Cocoa-Touch zeigen würden? Erstellen Sie eine UITableView und fügen Sie viele (viele tausend) Zeilen hinzu und sehen Sie, ob die Leistung sinkt, wenn Sie in jeder Zeile ein anderes Bild anzeigen. Vielleicht können die Leute dann Ihre Ergebnisse kommentieren. – stefanB

Antwort

86

tldr: ImageNamed ist in Ordnung. Es behandelt Speicher gut. Benutze es und hör auf dich zu sorgen.

Bearbeiten Nov 2012: Beachten Sie, dass diese Frage aus iOS 2.0 stammt! Bildanforderungen und Handhabung haben sich seither stark verändert. Retina macht Bilder größer und lädt sie etwas komplexer. Mit der integrierten Unterstützung für iPad und Retina-Bilder sollten Sie ImageNamed in Ihrem Code verwenden. Jetzt für die Nachwelt:

Die sister thread auf den Apple Dev Foren erhalten etwas besseren Verkehr. Speziell Rincewind hinzugefügt einige Autorität.

In iPhone OS 2.x gibt es Probleme, bei denen der imageNamed: -Cache auch nach einer Speicherwarnung nicht gelöscht wird. Zur gleichen Zeit hat + imageNamed: eine Menge Nutzen nicht für den Cache, aber für die Bequemlichkeit, die wahrscheinlich das Problem mehr vergrößert hat, als es hätte sein sollen.

während der Warnung

Auf der Geschwindigkeit vorne ein allgemeines Missverständnis ist, was los ist. Die größte Sache, die + imageNamed: does ist, entschlüsselt die Bilddaten aus der Quelldatei, die fast immer die Datengröße aufbläht (zum Beispiel kann eine PNG-Datei mit Bildschirmgröße einige Dutzend KB komprimieren, verbraucht aber mehr als eine halbe MB) dekomprimiert - Breite * Höhe * 4). Im Gegensatz dazu wird imageMithContentsOfFile: dieses Bild jedes Mal dekomprimieren, wenn die Bilddaten benötigt werden. Wie Sie sich vorstellen können, wenn Sie die Bilddaten nur einmal benötigen, haben Sie nichts gewonnen, außer dass eine im Cache gespeicherte Version des Bildes herumhängt und wahrscheinlich länger als Sie es brauchen. Wenn Sie jedoch ein großes Bild haben, das Sie häufig neu zeichnen müssen, dann gibt es Alternativen, obwohl die eine, die ich in erster Linie empfehlen würde, ist, dieses große Bild nicht zu zeichnen :). In Bezug auf das allgemeine Verhalten des Caches führt es einen Cache basierend auf dem Dateinamen durch (daher sollten zwei Instanzen von + imageNamed: mit dem gleichen Namen Verweise auf dieselben zwischengespeicherten Daten ergeben) und der Cache wird dynamisch wie Sie wachsen fordern Sie mehr Bilder über + imageNamed an :. Auf iPhone OS 2.x verhindert ein Fehler, dass der Cache geschrumpft wird, wenn eine Speicherwarnung empfangen wird.

und

Mein Verständnis ist, dass die + imagenamed: Cache sollte Speicher Warnungen auf dem iPhone OS 3.0 respektieren. Testen Sie es, wenn Sie eine Chance haben, und melden Sie Fehler, wenn Sie feststellen, dass dies nicht der Fall ist.

Also, da hast du es. imageNamed: Wird deine Fenster nicht zerschlagen oder deine Kinder ermorden. Es ist ziemlich einfach, aber es ist ein Optimierungswerkzeug. Leider ist es schlecht benannt und es gibt kein equivaluent, die so einfach zu bedienen ist - damit die Menschen sie überstrapazieren und aufregen, wenn es einfach macht seinen Job

ich eine Kategorie zu UIImage fügte hinzu, dass 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 einen Beispielcode, um Ihre eigene optimierte Version zu erstellen. Ich kann nicht sehen, dass es die Wartehase wert ist, aber hier ist es der Vollständigkeit halber.

Der Kompromiss mit diesem Code ist, dass das dekodierte Bild mehr Speicher verwendet, aber das Rendern ist schneller.

+0

Es scheint, dass [UIImage imageNamed:] auf iOS11 Bilder aus dem Cache nicht löscht, wenn Bilder aus dem xcasset-Katalog stammen. Dies führt zu Abstürzen aufgrund von nicht genügend Arbeitsspeicher. –

5

Meiner Erfahrung nach reagiert der von imageNamed erstellte Image-Cache nicht auf Speicherwarnungen. Ich hatte zwei Anwendungen, die so schlank waren, wie ich sie bei der Verwaltung von Mems bekommen konnte, aber trotzdem unerklärlicherweise abstürzten, weil sie nicht genügend Speicher hatten. Als ich ImageNamed nicht mehr verwendete, um die Bilder zu laden, wurden beide Anwendungen dramatisch stabiler.

Ich gebe zu, dass beide Anwendungen etwas große Bilder geladen, aber nichts, das völlig ungewöhnlich wäre. In der ersten Anwendung habe ich das Caching einfach übersprungen, weil es unwahrscheinlich war, dass ein Benutzer zweimal zum selben Bild zurückkam. In der zweiten Phase habe ich eine wirklich einfache Caching-Klasse erstellt, die genau das tut, was Sie erwähnt haben - indem ich UIImages in einem NSMutableDictionary verwalte und dann den Inhalt lösche, wenn ich eine Speicherwarnung erhalten habe. Wenn imageNamed: so cachen würde, hätte ich kein Performance-Upgrade gesehen. All dies lief auf 2.2 - ich weiß nicht, ob es 3.0 Auswirkungen darauf gibt.

Sie können meine andere Frage, um dieses Problem von meiner ersten App finden Sie hier: StackOverflow question about UIImage cacheing

Ein weiterer Hinweis - Interface verwendet imagenamed unter der Decke. Etwas, das Sie beachten sollten, wenn Sie auf dieses Problem stoßen.

+0

Ich sah das gleiche Verhalten und das Lesen von der Datei direkt gelöst. Auch passiert es, wenn ich versuche, ein sehr großes Bild zu laden - 11.456 x 3.226 px, 15MB. Meine Theorie ist, dass dem System während des ImageNamed-Cache-Vorgangs nicht genügend Speicher zur Verfügung steht. Und für diesen Fall ist kein Handling eingebaut. – Dogweather