2016-03-31 17 views
7

Ho sviluppato un'applicazione che mostra "schede a schermo intero" in un UICollectionView come Tinder. La carta contiene un'immagine e del testo. Stavo caricando l'immagine usando il metodo nella cella di UICollectionView.Precaricamento immagine in iOS

Tuttavia, questo non mi ha dato buone prestazioni poiché le immagini erano per lo più caricate quando l'utente era su una scheda. Ho quindi usato la coda SDWebImagePrefetcher prefetch per fare questo nel modo seguente: -

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 
    } 
} 

Questa funzione viene chiamata quando le terre utente su una particolare scheda. La coda di prefetching gestisce automaticamente non scaricare le immagini nella cache, quindi non devo preoccuparmene. Insieme a questo sto anche usando il sd_setImageWithURL in cellForItemAtIndexPath per raccogliere l'immagine scaricata dalla cache.

Questa è una soluzione migliore poiché ora sto pre-caricando le immagini quando l'utente è su una scheda. Tuttavia questa è una coda parallela. Il che significa immagine n. indice + 20 potrebbe essere caricato prima dell'immagine corrente e l'utente potrebbe dover attendere l'immagine. Anche l'app diventa un po 'più lenta se l'utente scorre oltre 50 carte e anche l'utilizzo della memoria continua a salire.

Qualcuno può suggerire miglioramenti a questo o un algoritmo migliore?

Grazie

risposta

1

Io suggerirei di gestire la propria coda, il salvataggio delle immagini su disco, poi il loro caricamento da disco.

Invece di una coda in parallelo, utilizzare una coda di serie, o almeno abbassare il numero di connessioni in parallelo

+0

Grazie Michael. In che modo aggiungere la mia coda risolve il problema poiché SDWebImage fornisce una coda ottimizzata. Ho provato a utilizzare una coda seriale, ma si stava rivelando troppo lento. Ho anche provato a giocare con il numero di immagini caricate, ma questo non aiutava –

5

Scarica l'immagine sulla carta corrente con sd_setImageWithURL e nel gestore di completamento avviare il download della coda prefetching . In questo modo l'immagine corrente ha sempre la priorità più alta e non tarda.

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

Se l'immagine corrente è già stata scaricata, SDWebImage lo riconosce e lo preleva dalla cache.

L'altro problema con il ritardo e l'elevato consumo di memoria può essere risolto riducendo il numero di immagini precaricate. 20 è abbastanza alto, 5 dovrebbe essere sufficiente, ma ciò dipende dalle dimensioni dell'immagine, dalla velocità della rete, ecc ...

Un'altra cosa: SDWebImage ha una proprietà maxConcurrentOperationCount. Inizia con 1, prova, aumenta a 2, prova, aumenta ... e così via. Finché non trovi il punto in cui si ritarda.

+0

Grazie a @Darko. Questo risolverebbe il problema solo per l'immagine attuale, vero? Ho provato il prefetch di sole 5 immagini ma causava anche problemi di memoria e ritardo. –

+0

Prova il prefetching di uno solo. Quanto sono grandi le immagini? E qual è la solita velocità di rete? – Darko

+0

Le immagini hanno una dimensione inferiore a 100 KB e la velocità di rete prevista è 3G/4G/Wi-Fi –

1

Ho risolto un problema analogo sull'app che sto sviluppando. Sulla mia app ci sono migliaia di utenti, e ognuno può avere un avatar.

Per migliorare le prestazioni, ho sviluppato un controller a 3 livelli per gestire la richiesta di avatar.

In un primo momento, controllo NSCache (tutti gli avatar più recenti che ho salvato su NSCache, gestito da iOS, quindi non mi devo preoccupare di rilasciare la memoria cache ogni volta che è necessario). Hai solo bisogno di definire un paio di parametri per configurare NSCache.

Se l'avatar non viene trovato su NSCache, controllo sul mio Db (Sqlite) locale, dove gli avatar più usati sono salvati come campi Blob. Basta ricordare che a volte è necessario eseguire un clean up sul Db locale, rilasciando i vecchi dati per salvare la memoria del dispositivo.

Se non viene ancora trovato, salvi la richiesta su una coda utilizzando il metodo LIFO (ultimo nella prima uscita). Significa che ogni volta che l'utente locale sta scorrendo l'elenco degli utenti, gli avatar degli utenti correnti sullo schermo devono essere ottenuti prima di quelli che sono già usciti dalla schermata di visualizzazione tabella.

Ancora una volta, per aumentare nuovamente le prestazioni (decidere su vostra scelta), mentre l'utente sta scorrendo velocemente lo schermo non richiedo alcun download. Inizio a richiedere i download ogni volta che l'utente rallenta lo scorrimento della vista tabella. Oltre a ciò, limito il numero di download paralleli. Un nuovo download viene avviato solo quando si apre uno spazio di download (in caso di esito positivo o negativo).

Queste ottimizzazioni funzionano molto bene per me, la mia app è in esecuzione leggera.

Spero che possa aiutarti.

+0

Grazie Jorg. La mia soluzione sembra essere una soluzione a due livelli. SDImageCache è un'alternativa a NSCache e ho anche implementato una coda come secondo livello. In che modo l'aggiunta di uno strato SQLite qui migliora le prestazioni? –

+0

Ciao Rajeev. Ho aggiunto SQLite per casi come riavvio del dispositivo, riavvio dell'app o anche se iOS lo ha rilasciato da NSCache. In questi casi, senza SQLite l'App dovrebbe scaricare di nuovo gli avatar mancanti dai servizi web/AWS. Per evitare ciò, se l'avatar è già presente sul db locale (SQLite), l'App non avrà bisogno di scaricarlo nuovamente. Otterrà solo l'avatar dal db locale, salverà su NSCache e restituirà l'immagine all'App. –