Working with Images in CloudKit

Marcus Smith
Frozen Fire Studios
3 min readMar 1, 2016

--

I mentioned in a previous post that working with images in iCloud can be a bit of a challenge, particularly having a lack of server-side code to resize images and asset transfer limits. I wanted to go into this with a bit more detail, going into how images in CloudKit work and a few tricks that we used to overcome these challenges.

CKAssets

Data in CloudKit is stored using CKRecords, but to store an image in iCloud you need to use CloudKit’s CKAsset class. CKAssets are used to store large files (Apple recommends anything more than a few kilobytes in size, but no more than 250MB) in iCloud and associate them with specific CKRecords.

When downloading a record with a CKAsset, the asset’s data is temporarily saved to disk, but it is not guaranteed to stay there long, and may be cleaned up when the system needs to free memory. So it is definitely a good idea to get the data from the asset as soon as the record is downloaded. The file can be accessed from the asset’s fileURL property. Getting an image from a CKAsset can take a little unwrapping, but it is a straightforward conversion:

Similarly, when you want to create a CKAsset, you need a fileURL where your data is saved.

Converting CKAssets, NSData and UIImages back and forth can be a bit of a pain, managing temporary fileURLs can be too. I have a few convenience extensions that I wrote to make working with UIImages and CKAssets easier:

The extension on UIImage takes care of saving images to data and writing them to a unique, temporary file URL. I use the ImageFileType enum to give a little control over how the images are saved. The extension on CKAsset works with the UIImage extension, letting me work with images and assets directly.

Desired Keys

When using CKOperations to fetch CKRecords, the operations’ desiredKeys property can be useful in only getting the data you need. This can be particularly useful when working with images or other CKAssets that you might not want to download everytime you retrieve a record. In our app Atoll, we save multiple image copies at various sizes to the same CKRecord so that they can all be linked to the same recordID. However we almost always only need one particular size of an image at a time. Here’s an example of how using the desiredKeys property on our fetch operation limits our download to only the image we need.

In this code example, images of different sizes are saved to the same CKRecord, but then can be fetched individually by the record’s recordID and the desired size. Instead of the entire record being fetched, only the asset matching that specific size is downloaded. This makes it easy to organize your images, without having to eat up too much bandwidth downloading all related images at once.

Long Lived Operations

In the example above, I used CKDatabase’s saveRecord convenience method to keep the code short, but when saving records with many images on them I recommend using a CKModifyRecordsOperation instead. As a CKOperation it will continue to run in the background, and you have the option to make it longLived, ensuring that it will complete even if your app is terminated before it can finish. The setup for these operations is pretty simple and is definitely a bonus for working with CloudKit. I have some more information about using Long Lived Operations in another post.

TL;DR

When working on Atoll, we ran into some challenges in working with images in CloudKit: lack of server side code to resize images and the amount of asset transfer we required. To deal with images of different sizes, we created CKAssets with our resized images, and saved them all to the same CKRecord. To keep our asset transfer low while accessing these images, we used CKFetchRecordsOperation’s desiredKeys property to make sure we are only downloading the minimum information that we need.

Notes

  • CKAssets cannot be deleted from iCloud directly. To have assets removed from iCloud, remove them from your records (save the record with nil for the asset’s key). Once no more records are pointing to a specific asset, iCloud will take care of cleaning up the asset “at some point in the future”.
  • Long Lived Operations are available starting in iOS 9.3

--

--