简体   繁体   中英

Optimally preloading / prefetching images in UICollectionView and UITableView

I have what I would imagine is a very common situation that I expected to be easy to solve - an app with a UICollectionView, with an image in each cell that is fetched from an API on a web server via http/https.

I'm attempting to implement iOS 10's prefetching in UICollectionView , so that images are that are likely to be required are requested ahead of time.

It seems to me that there are various requirements that should be met for optimal prefetching:

  1. Fetching of images that are actually immediately required should always be prioritised above speculative prefetching, even when the image is already in a queue to be fetched.
  2. When iOS tells us a particular image is no longer required to be prefetched, it (and only it) should be removed from the prefetch queue.
  3. If an image is requested it should always be delivered unless /all/ requests for it are canceled (easy to get wrong if one image is used in multiple cells or multiple view controllers).
  4. Prioritised fetching should be aborted if didEndDisplaying is called (but, if prefetching was requested and wasn't cancelled, the image should presumably be left in the queue at a lower priority).
  5. Various common requirements that simply relate to image loading - eg. don't flood the underlying system with prefetch requests that will end up taking bandwidth and server slots away from images that are required immediately.

I've looked at various existing libraries like SDWebImage and Kingfisher , and was surprised that there doesn't appear to be any way to meet the above requirements easily with either library.

For example, SDWebImage doesn't meet the second requirement - you can only cancel all prefetching , or you must create a pre-fetcher per image (which then means various other SDWebImage features, like limiting the number of concurrent requests of pre-fetched images - ie. requirement 5 - no longer work.)

Is this really a hard problem? Did I miss some obvious solution? Am I overthinking the requirements?

It seems you'll need to implement your own priority if the latest indexpath passed from prefetchItemsAt indexPaths doesn't suffice.

Requirements 1, 2, 3 and be accomplished using a Priority Queue (Sorted Heap). Requirement 4 depends on your implementation the Priority Queue. 5 is quite broad and vague, just limit the number of calls to your method for fetching. The Priority Queue takes a generic type so you can use it with an object/class that has properties for the items you wish to fetch, below I just use IndexPath.row for simplicity.

Create a priority queue that will serve as a mediator between your datasource and the cache.

then set the data to fetch from your DataSource by peeking/dequeuing the priority queue and storing in Kingfisher. Your DataSource -> PriorityQueue -> Kingfisher -> Cell

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 = ...

        }
    }
}

make sure you initialize the priority queue with a sort function.

you can get a prebuilt priority queue from here you will also need a heap to create the priority queue.

more on priority Queues and heap sorting

Without the code in question it is difficult to offer an effective solution. I hope this helps, cheers and good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM