Introduction to Lazy Loading
What is lazy loading?
A little introduction of lazy loading is it is a design pattern to defer the initialization of an object until the point at which it is needed. In simple words create objects when it is needed.
Problems to Tackle
Before talking about lazy loading of images, I want to mention about problems / issues associated in handling images in UITableView in iOS. These are:
- Scrolling is blocked / interrupted – Downloading images from server OR loading from device local storage is heavy task and it may take some time. If you load images directly in cellForRowAtIndexPath() method of UITableView then it blocks the UI thread and your UITableView scroll will be interrupted and not smooth. You need a mechanism to load images in a worker (separate) thread and show a place holder image until the image in not downloaded and placed in memory for fast access. Remember accessing images from Hard disk may also takes some time.
- App Heap Memory can overshoot – If we load many images in memory for faster access by UITableView, then memory (heap memory) allocated to the application might overshoot and app will crash with Out of Memory (OOM) error.
- Work with Recycling of Views can be tricky – When image is downloaded we need to decide when to set a particular image in its ImageView of that row it is meant for. It may be possible that the ImageView object will recycle and it is given to another image and we end up showing wrong image.
Solution
Memory Locations – Space Vs Accessibility:
There are 3 locations where images are stored. Their comparison on Memory space availability and Accessibility speed is given below:
- Server (Memory Space is HIGH but Accessibility is SLOW)
- Hard Disk on Mobile (Memory Space is MEDIUM and Accessibility is MEDIUM)
- Heap Memory (Memory Space is LOW and Accessibility is FAST)
We need to create a balance among above 3 locations for optimum utilization of accessibility and memory space.
Mappings:
2 Mappings are required to manage the show. I have given them names. These are
- Bitmap Cache Map (Unique ImageURL of Row TO Bitmap of Image) – NSCache class provided in iOS SDK to store images in memory (Heap) will be used here. NSCache will act as cache and will also recycle the images after a certain limit is reached.
- Image Download Tracker (Image URL TO Object of NSOperation) – This will map the URL and the status of image that is being downloaded from the URL. It is possible that request to download the same image comes and that image is already in process of downloading. This tracker will help to ignore such requests.
Sequence of Steps:
1. When user comes to UITableView the cellForRowAtIndexPath is fired for a single cell. Here we will first check that if image is available in the object of NSCache class against the key which will be the image URL. If it is there then we will get the value of UIImage and set on cell’s imageView.
2. If image is not available in object of NSCache class then in that case we will make a object of NSOperation Class and add in Queue whose task is to fetch image either from the Hard Disk or from the server.
3. When this operation will start we will first check that if image is available in local storage. If image id not present here we first download the image and then return back to the ViewController via delegate method taking object of UIImage.
4. If the image is available on device local storage Or it is available after downloading from server, it is put in Bitmap Cache Map and send for display.
CHECKPOINT 2 of 3 – It is possible that by the time image is to be loaded from device local storage (Either already available OR after download), UITableView has been scrolled by the user and ImageView object is recycled and allocated to other row with a different ID. Mapping of ImageView and ID is checked in ImageView Recycler Map for that. If ImageView has been recycled, we don’t need to place this image in Bitmap Cache Map. But keep it on hard disk.
6. To display the image on ImageView we post a Runnable on the UI Thread using the Handler.
CHECKPOINT 3 of 3 – Just before image is set on ImageView we again check in ImageView Recycler Map if the Mapping of ImageView (IV1) and Id (ID1) exists. If the mapping exists we set the image on ImageView else the place holder (default) image is set.