Preheating (prefetching/precaching) resources is an effective way to improve user experience for many apps. Prefetching is a common term that refers to software that downloads data ahead of time in anticipation of its use.
One of the resources that you might want to prefetch for your users is images. In this post I’m going to be talking about prefetching images in a UICollectionView. More specifically, dynamically prefetching images when the user is scrolling the content.
Warning: this post is a bit outdated because of the Nuke and Preheat changes.
Preheating (prefetching/precaching) means loading data ahead of time in anticipation of its use
It’s possible to automate preheating in a UICollectionView and UITableView
The actual implementation detects when the user scrolls the content, calculates the preheat window, finds out which cells are going to be displayed in it, and calls a handler that starts/stops image requests
Preheat & Nuke provide a set of tools for preheating images
Preheating in a UICollectionView
It’s relatively simple to automate preheating in a collection view.
Here’s an outline of what we need to do:
Detect when the user is scrolling
Calculate an area (preheat window) just outside of the viewport in the direction in which the user is scrolling
Find out which cells are going to be displayed in it
Signal the delegate with index paths for these cells
Calculating Preheat Window
I’m not posting the entire implementation here, just some more interesting bits.
A UICollectionView is a UIScrollView subclass which means that we can detect when the user scrolls the content by observing changes to contentOffset property using KVO.
The next step is to calculate a preheat window in the current scroll direction (works for a UICollectionViewFlowLayout only):
After we calculated a preheat window we find out which cells are going to be displayed in it by using layoutAttributesForElementsInRect(_) method of UICollectionView class. It also makes sense to sort index paths by the distance to the viewport.
Updating Preheat Window
It becomes a little more complicated if you want to update preheat window dynamically when the user scrolls the content.
First, we need to keep track of the current preheat window, and update it only when the user scrolls far enough from the point where it was calculated. Otherwise, we would be recalculating it each time we observe a change in a contentOffset property.
Second, we might make it more convenient for the delegate by calculating a diff between previous preheat window and the current one (in terms of index paths):
Preheat & Nuke
The full implementation of preheating is available in Preheat library. Preheat consists of a single generic PreheatController class that supports both UICollectionView and UITableView.
You can use Preheat with any image loading library, including Nuke which it way designed for. Nuke provides a set of self-explanatory methods for precaching image which are inspired by the PHImageManager class:
When you call startPreheatingImages(_) method, Nuke starts to load and cache images for the given requests. Nuke caches images with the exact target size, content mode, and filters provided in the request. At any time afterward, you can create tasks with equivalent requests - for each of the requests Nuke would either return a cached image, or add another observer to the existing preheating task.
Nuke guarantees that preheating tasks never interfere with normal (non-preheating) tasks. For instance, preheating tasks don’t start executing until there are no outstanding non-preheating tasks. There is also a limit of concurrent preheating tasks.
Here is an example of how you might implement preheating in your application using Preheat & Nuke:
The idea of automating preheating was inspired by Apple’s Photos framework sample.