iCloud Storage gotcha: Apple inserts a UUID into the filename when storing

My new flash cards app, Fresh Cards, uses iCloud for syncing data between macOS and iOS devices. I’m learning a lot about how to use iCloud Storage, and there are quite a few gotchas and documentation is kind of sparse online, so I figured I’d go through something that I just learned about it here.

Apple recommends using an NSMetadataQuery to keep track of any changes to the iCloud storage folder. Whenever files change in the cloud, any query notification handlers you’ve set up will be called. This gives you an opportunity to go through the list of remote files and see if there’s anything that changed of interest to your app.

The way I handle changes in the cloud is to enumerate the results in the NSMetadataQuery object. I call query.result(at: index) to get each item. Each item is just a NSMetadataItem and you can call value(forAttribute:) on each item to get a whole bunch of info:

  • NSMetadataItemFSNameKey to get the filename
  • NSMetadataItemFSContentChangeDateKey to get the last modified date
  • NSMetadataItemURLKey to get the file URL on disk
  • NSMetadataItemPathKey to get the path to the file on disk (same as file URL but in path form)
  • NSMetadataItemFSSizeKey to get the file size

In my code, one thing I was doing that was bad was using the file URL to determine the filename. This isn’t necessary since NSMetadataItemFSNameKey already gives you the filename. I didn’t realize this at the time.

Anyway, you’d think that the filename in the file URL would be the same as the NSMetadataItemFSNameKey value, but it’s not! Apple actually inserts a UUID into the filename here. I understand why they’d do this. Whenever you upload a file to the iCloud storage, they probably do this to avoid collisions if more than one device is uploading the same file. At some point, they have some conflict resolution and they essentially just “point” to the winner.

For my purposes, I was uploading files that looked like “B565B1E0-B5B8-420D-9792-0CE51911697C.journal”. I had my own scheme where I would use a UUID to make filenames unique as well. But, since Apple was also inserting a UUID into the filename, I started noticing the file paths and file URLs provided by NSMetadataQuery as looking like “B565B1E0-B5B8-420D-9792-0CE51911697C 20CE63AC-AECF-43B9-B5B0-382DD1C8C49B.journal” instead. This threw me off since I thought my app was uploading these errant files. Once I figured out that Apple was doing this, I was able to correct my app behavior to just use the filename from the NSMetadataItemFSNameKey attribute, which is always what you expect it to be (i.e. without the additional UUID inserted).

tl;dr – Apple inserts a UUID into your filenames when storing iCloud Storage, so “foo.txt” becomes “foo 2445A03E-15B0-4DB8-ACC4-62A29B8DE9C5.txt”. Make sure you use NSMetadataItemFSNameKey as the actual filename and not the lastPathComponent of the fileURL or path you get from the metadata item.