2016-03-31 5 views
7

Ich habe eine App entwickelt, die "Vollbild-Karten" in einem UICollectionView wie Tinder zeigt. Die Karte enthält ein Bild und etwas Text. Ich habe das Bild geladen SDWebImage 's sd_setImageWithURL Methode in der Zelle UICollectionView.Bild Vorladen in iOS

Allerdings gab mir das keine gute Leistung, da die Bilder meist geladen wurden, wenn der Benutzer auf einer Karte war. Ich habe daher die SDWebImagePrefetcher Prefetch-Warteschlange, dies zu tun, wie folgt: -

func startImagePreloadingOperationForIndex(index:Int) 
{ 
    let numberOfImagesToBePreloadedOnEachSide = 20 
    var previousIndex = index - numberOfImagesToBePreloadedOnEachSide 
    var nextIndex = index + numberOfImagesToBePreloadedOnEachSide 

    if previousIndex < 0 
    { 
     previousIndex = 0 
    } 
    if nextIndex >= currentNewsCollection.count 
    { 
     nextIndex = currentNewsCollection.count - 1 
    } 

    if previousIndex >= nextIndex || currentNewsCollection.isEmpty 
    { 
     return 
    } 
    let arrayOfNewsStories = currentNewsCollection[previousIndex...nextIndex] 

    let arrayOfImageURLs = arrayOfNewsStories.map({ ImageUtility.getImageStringForNewsStory($0) }) 

    SDWebImagePrefetcher.sharedImagePrefetcher().prefetchURLs(arrayOfImageURLs, progress: { (x, y) -> Void in 
     }) { (x, y) -> Void in 
    } 
} 

Diese Funktion, wenn der Benutzer landet auf einer bestimmten Karte genannt wird. Die Vorablesewarteschlange verwaltet automatisch, dass keine Bilder im Cache heruntergeladen werden, sodass ich mich nicht darum kümmern muss. Zusammen mit diesem verwende ich auch die sd_setImageWithURL in cellForItemAtIndexPath, um das heruntergeladene Bild aus dem Cache abzuholen.

Dies ist eine bessere Lösung, da ich jetzt Bilder vorspeichern, wenn der Benutzer auf einer Karte ist. Dies ist jedoch eine parallele Warteschlange. Was bedeutet Bild-Nr. index + 20 könnte vor dem aktuellen Bild geladen werden und der Benutzer müsste auf das Bild warten. Auch wird die App ein wenig nach hinten verschoben, wenn der Benutzer mehr als 50 Karten scrollt und die Speicherauslastung ebenfalls steigt.

Kann jemand bitte Verbesserungen zu diesem oder einem besseren Algorithmus vorschlagen?

Dank

Antwort

1

ich Ihre eigene Warteschlange Handhabung würde vorschlagen, Bilder auf der Festplatte speichern, dann von der Festplatte geladen werden.

Anstelle einer parallelen Warteschlange, verwenden eine serielle Warteschlange oder zumindest wiederum die Anzahl der parallelen Verbindungen unten

+0

Danke Michael. Wie würde das Hinzufügen meiner eigenen Warteschlange das Problem lösen, da SDWebImage eine optimierte Warteschlange bereitstellt. Ich habe versucht, eine serielle Warteschlange zu verwenden, aber das erwies sich als zu langsam. Ich habe auch versucht, mit der Anzahl der geladenen Bilder herumzuspielen, aber das hat nicht geholfen –

5

Herunterladen des Bildes auf der aktuellen Karte mit sd_setImageWithURL und in dem Abschluss-Handler das Herunterladen der Vorabruf-Warteschlange starten . Auf diese Weise genießt das aktuelle Bild immer die höchste Priorität und verzögert sich nicht.

currentCardImageView.sd_setImageWithURL(url) { (image, error, imageCacheType, url) in 
    // start prefetching here 
} 

Wenn das aktuelle Bild bereits heruntergeladen wurde, erkennt SDWebImage dies und ruft es aus dem Cache ab.

Das andere Problem mit der Verzögerung und dem hohen Speicherverbrauch kann möglicherweise gelöst werden, indem die Anzahl der vorab abgerufenen Bilder reduziert wird. 20 ist ziemlich hoch, 5 sollte ausreichen, aber das hängt von der Bildgröße, Netzwerkgeschwindigkeit, etc ..

Eine andere Sache: SDWebImage hat eine maxConcurrentOperationCount-Eigenschaft. Beginnen Sie mit 1, testen Sie, erhöhen Sie auf 2, testen Sie, erhöhen Sie ... und so weiter. Bis Sie den Punkt finden, der es hinkt.

+0

Danke @Darko. Dies würde nur das Problem für das aktuelle Bild lösen, oder? Ich habe versucht, nur 5 Bilder vorabzuholen, aber das verursachte auch Speicher- und Lag-Probleme. –

+0

Probieren Sie nur einen aus. Wie groß sind die Bilder? Und wie ist die übliche Netzwerkgeschwindigkeit? – Darko

+0

Die Bilder sind weniger als 100 KB groß und die erwartete Netzwerkgeschwindigkeit ist 3G/4G/Wi-Fi –

1

Ich löste ein analoges Problem auf der App, die ich entwickle. Auf meiner App gibt es Tausende von Benutzern, und jeder kann einen Avatar haben.

Um die Leistung zu verbessern, habe ich einen 3-Stufen-Controller entwickelt, um die Avatar-Anfrage zu verwalten.

Zuerst überprüfe ich den NSCache (all die zuletzt verwendeten Avatare, die ich in NSCache speichere - was von iOS gehandhabt wird, so muss ich mich nicht um die Freigabe von Cache-Speicher kümmern, wenn nötig). Sie müssen nur einige Parameter definieren, um NSCache zu konfigurieren.

Wenn der Avatar nicht auf NSCache gefunden wird, überprüfe ich meinen lokalen Db (Sqlite), wo die zuletzt verwendeten Avatare als Blob-Felder gespeichert werden. Denken Sie daran, dass Sie manchmal ein lokales Db aufräumen müssen, indem Sie die alten Daten freigeben, um den Gerätespeicher zu sichern.

Wenn immer noch nicht gefunden, speichere ich die Anfrage in einer Warteschlange mit der LIFO-Methode (last in first out). Wenn der lokale Benutzer die Benutzerliste scrollt, sollten die Avatare der aktuellen Benutzer auf dem Bildschirm vor denen angezeigt werden, die bereits aus dem Bildschirm der Tabellenansicht entfernt wurden.

Noch einmal, um die Leistung wieder zu erhöhen (entscheiden Sie auf Ihre Wahl), während der Benutzer schnell scrollt den Bildschirm, ich fordere keinen Download. Ich beginne gerade, Downloads anzufordern, wenn der Benutzer den Tabellenansichtslauf verlangsamt. Darüber hinaus beschränke ich die Anzahl der parallelen Downloads. Ein neuer Download wird nur gestartet, wenn ein Download-Slot geöffnet wird (Erfolg oder Fehlschlag).

Diese Optimierungen funktionieren sehr gut für mich, meine App läuft Licht.

Ich hoffe, dass es Ihnen helfen kann.

+0

Danke Jorg. Meine Lösung scheint eine zweistufige Lösung zu sein. Der SDImageCache ist eine Alternative zum NSCache und ich habe auch eine Warteschlange als zweite Ebene implementiert. Wie verbessert das Hinzufügen einer SQLite-Ebene die Leistung? –

+0

Hallo Rajeev. Ich habe SQLite für Fälle wie Neustart des Geräts, Neustarten der App oder sogar, ob das iOS es von NSCache freigegeben hat. In diesem Fall sollte die App ohne SQLite die verpassten Avatare erneut von den Webdiensten/AWS herunterladen. Um dies zu vermeiden, muss die App, wenn sich der Avatar bereits auf der lokalen Datenbank (SQLite) befindet, sie nicht erneut herunterladen. Es wird nur den Avatar aus der lokalen Datenbank holen, NSCache speichern und das Bild zu App zurückgeben. –