2017-07-26 3 views
5

J'ai ce que j'imagine être une situation très commune que je pensais être facile à résoudre - une application avec un UICollectionView, avec une image dans chaque cellule qui est extraite d'une API sur un serveur web via http/https.Pré-chargement/prélecture des images de façon optimale dans UICollectionView et UITableView

Je tente d'implémenter iOS 10 prefetching in UICollectionView, de sorte que les images qui sont susceptibles d'être nécessaires sont demandées à l'avance.

Il me semble qu'il ya diverses exigences qui doivent être remplies pour que le préchargement optimal:

  1. Récupérer les images qui sont effectivement immédiatement nécessaires devrait toujours être une priorité au-dessus de préchargement spéculative, même si l'image est déjà dans une file d'attente à récupérer.
  2. Lorsque iOS nous dit qu'une image particulière n'a plus besoin d'être préchargée, elle (et seulement elle) doit être supprimée de la file d'attente de prélecture.
  3. Si une image est demandée, elle doit toujours être fournie à moins que/toutes/les requêtes ne soient annulées (ce qui peut facilement se produire si une image est utilisée dans plusieurs cellules ou plusieurs contrôleurs de vue).
  4. La récupération priorisée doit être annulée si didEndDisplaying est appelé (mais si la pré-extraction a été demandée et n'a pas été annulée, l'image doit probablement être laissée dans la file d'attente à une priorité inférieure).
  5. Diverses exigences communes qui se rapportent simplement au chargement de l'image - par ex. Ne pas inonder le système sous-jacent avec des demandes de prélecture qui finiront par prendre la bande passante et les emplacements de serveur loin des images qui sont requises immédiatement.

Je l'ai regardé dans diverses bibliothèques existantes comme SDWebImage et Kingfisher, et a été surpris qu'il ne semble pas être un moyen de répondre aux exigences ci-dessus facilement avec soit la bibliothèque. Par exemple, SDWebImage ne répond pas à la deuxième exigence - vous ne pouvez que cancel all prefetching, ou vous devez créer un pré-extracteur par image (ce qui signifie alors diverses autres fonctionnalités de SDWebImage, comme la limitation du nombre de demandes simultanées de pré- images récupérées - c'est-à-dire l'exigence 5 - ne fonctionne plus.)

Est-ce vraiment un problème? Ai-je manqué une solution évidente? Suis-je en train de repenser les exigences?

Répondre

0

Il semble que vous aurez besoin d'implémenter votre propre priorité si le dernier chemin d'index passé de prefetchItemsAt indexPaths ne suffit pas.

Exigences 1, 2, 3 et être accomplies en utilisant une file d'attente prioritaire (tas trié). L'exigence 4 dépend de votre implémentation de la file d'attente prioritaire. 5 est assez large et vague, il suffit de limiter le nombre d'appels à votre méthode pour aller chercher. La file d'attente de priorité prend un type générique de sorte que vous pouvez l'utiliser avec un objet/classe qui a des propriétés pour les éléments que vous souhaitez récupérer, ci-dessous, j'utilise simplement IndexPath.row pour plus de simplicité.

Créez une file d'attente prioritaire qui servira de médiateur entre votre source de données et le cache.

puis définissez les données à extraire à partir de votre DataSource en jetant un coup d'œil/en supprimant la file d'attente prioritaire et en l'enregistrant dans Kingfisher. Votre DataSource -> PriorityQueue -> Kingfisher -> Cellule

func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { 
    ... 
    for indexPath in IndexPaths { 
     //Add the indexPath to the top of the priority queue 
     //highest priority is determined by the sort function you used when initializing the priority queue. 
     priorityQueue?.enqueue(indexpath.row) 
    } 

    //Call your method for getting the properties 
    self.fetchObjectsByPriority() 
} 


func fetchObjectsByPriority() { 
     if let count = priorityQueue?.count { 
     for _ in 0...count { 

      //get the index 
      var index = self.priorityQueue?.dequeue() 
      //Alternatively .peek() with out dequeuing item 
      //get image data and store 
      dataSource[index].image = ... 

     } 
    } 
} 

assurez-vous d'initialiser la file d'attente prioritaire avec une fonction de tri.

Vous pouvez obtenir une file d'attente de priorité prédéfinie de here. Vous aurez également besoin d'un heap pour créer la file d'attente prioritaire.

plus sur priority Queues et heap sorting

Sans le code en question, il est difficile d'offrir une solution efficace. J'espère que cela aide, acclame et bonne chance!