Display state of iCloud files

I’m building a macOS app that displays a large grid of image thumbnails similar to Photos.

What is the recommended way to determine whether a file is locally available/downloaded without making a blocking call to the filesystem for every thumbnail?

Thanks!

Answered by Engineer in 890806022

For security-scoped-bookmark files, the best way is to track availability with the URL resource values plus an NSFilePresenter. The protocol has tools for monitoring cloud state changes:

@property (readonly, strong) NSSet<NSURLResourceKey> *observedPresentedItemUbiquityAttributes;  // macOS 10.13+
- (void)presentedItemDidChangeUbiquityAttributes:(NSSet<NSURLResourceKey> *)attributes;

You'll need to do some of the wiring yourself to keep things off the main thread:

  • Cells can read an in-memory cache synchronously
  • presentedItemDidChangeUbiquityAttributes: → re-fetch that item, update cache, refresh cell
  • Local files: check isUbiquitousItemKey once at bookmark resolution, classify as local.

For files inside your own iCloud container, NSMetadataQuery (NSMetadataQueryUbiquitousDocumentsScope) pushes batched update deltas with the cloud-state keys.

Some docs which may help:

First, I'd like to note this excerpt from the CKAsset documentation:

When you fetch a record that contains an asset, CloudKit stores the asset’s data in a staging area accessible to your app. Use the asset’s fileURL property to access its staged location. The system regularly deletes files in the staging area to reclaim disk space. To avoid this behavior, move the data into your app’s container as soon as you fetch it.

As you read (sync/query/fetch) CKRecords, you'll be updating your on-device database noting the presence of that data as it's downloaded, and you'll need to move the CKAsset files (e.g. thumbnail and any other image derivatives) into your app container. Your on-device database can then be used to feed your user interface, including whether a record has a thumbnail, etc.

Since I'm not an expert in it, I won't speak to the best ways to efficiently render large sets of data that potentially have file-backed content, but presumably SwiftUI has solutions for this.

Thanks. I should clarify that I’m not using CloudKit records or CKAsset.

My app stores security-scoped bookmarks to user-selected files. Some files are regular local Finder files, and some are files in iCloud Drive.

The UI is a large thumbnail grid. I maintain my own thumbnail cache, but I also want to display whether the original file is currently local, cloud-only, downloading, or unavailable.

Given that model, what is the recommended way on macOS to track the availability of iCloud Drive files without synchronously touching every original file while scrolling the grid?

For security-scoped-bookmark files, the best way is to track availability with the URL resource values plus an NSFilePresenter. The protocol has tools for monitoring cloud state changes:

@property (readonly, strong) NSSet<NSURLResourceKey> *observedPresentedItemUbiquityAttributes;  // macOS 10.13+
- (void)presentedItemDidChangeUbiquityAttributes:(NSSet<NSURLResourceKey> *)attributes;

You'll need to do some of the wiring yourself to keep things off the main thread:

  • Cells can read an in-memory cache synchronously
  • presentedItemDidChangeUbiquityAttributes: → re-fetch that item, update cache, refresh cell
  • Local files: check isUbiquitousItemKey once at bookmark resolution, classify as local.

For files inside your own iCloud container, NSMetadataQuery (NSMetadataQueryUbiquitousDocumentsScope) pushes batched update deltas with the cloud-state keys.

Some docs which may help:

Thanks, that helps.

I already use a NSFilePresenter on a root folder to track changes, so I could probably wire that to trigger cell refresh on presentedItemDidChangeUbiquityAttributes.

For the initial render of the grid, are you suggesting I somehow resolve the bookmarks and check the URL resource values in one large batch that populates a cache? Obviously one only wants to load the cells that will appear.

Display state of iCloud files
 
 
Q