Ultra memory-friendly thumbnails on iOS

Avoid blowing through the memory budget, even in extensions

This week Retro has a fresh new look to the Friends widget. Where we used to only show a single post, we now show a grid of recent posts from your friends.

It’s not super well documented, but widgets have size restrictions on the images you can add to timeline entries. This combined with the very low memory limits imposed on iOS extensions (~30MB) has historically made loading images into widgets a bit of a headache. We got crashes while downscaling very often, even when using the efficient CGImageSource thumbnailing methods.

So, how do we go from showing one image per widget to showing a whole grid without blowing up the memory limit?

In the past I’ve heard of the QuickLook framework’s thumbnailing methods being designed explicitly for the low memory requirements of extensions, but nothing I’d worked on had warranted using them. To enable Retro’s grid widget I decided to give them another shot.

Per the docs (here and here), in order to get out-of-process thumbnailing you have to use the -saveBestRepresentationForRequest:toFileAtURL:... method that operates on files. You give it a file, and it hands you a thumbnail file back. I wasn’t expecting this API to work given that I hadn’t heard much about it before, but to my surprise it does exactly what it claims! The widget, even when processing many images, now barely consumes memory where it used to have a nonzero chance of running out.

Before, OOMing

After, comfortably under the memory limit

If you’re working in a memory constrained environment like widgets or extensions on iOS I highly recommend checking this out.