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.

Beta testing continues for Fresh Cards!

Work continues on Fresh Cards! Fresh Cards is a new flash card app I’m developing for macOS and iOS.

I’ve been refining the lesson UI, trying to make it easier and easier to use. At the moment, the app has three tabs per deck, one for the next lesson info, one for the list of cards, and one for the stats. After using this app for several weeks now, I’ve realized that I’m always switching between the lesson info and the stats screen. It dawned on me that it makes sense to combine them for a one-stop shop.

Here’s a sneak peek at a design mockup I put together last night in Inkscape:

If you’re in the app to view a lesson, you’ll see it right away. However, if you’ve already done your lesson and just want to see info on your next lesson or other trends, you’ll see them right away too.

Simultaneously (yes, I’m doing all of these tasks at the same time), I’m getting the iPhone version of the app up and running. There’s a lot of shared code, so the majority of this work is building up the UI for iOS. Nearly a year ago I was working on an iPhone flash card app (sort of v1 of this project), and thankfully I’m able to reuse a lot of the UI here to save time.

Check out SlouchDB

For my apps Lil Todo, ForeverList/Nested Notes, and Little Phrase Book, I created a simple database system that can be synced easily across multiple devices using a cloud store like Dropbox. Well, I’m happy to announce that I’ve been working on generalizing the database/sync engine for those apps and have opened sourced it.

Check out my new Swift-based SlouchDB. It’s a decentralized, syncable journal-based database meant for single-user, multi-client scenarios like the apps mentioned above. You can use it for Mac and iOS apps! It’s available as a CocoaPod, so you can easily consume it that way as well.

ForeverList update: You can now reorder notes in a list

I spent about an hour and a half tonight adding reordering of notes. You can now pick up a note and re-position it relative to other notes in the list. I had to add code not only in the UI support this, but also back-end support in the storage to record the reordering of notes in a list.

In the future you’ll be able to drag and drop entries from one list to another as well, but this isn’t supported yet. That particular feature will be great because the whole purpose of this app is to allow you to organize your notes hierarchically in a tree, so there’s a big hole if you can’t pick up a note and move it to a sub-tree.

I’ve been coding on a tear in the last few days, but that’s led to a build-up of technical debt. I think it’s acceptable as I get a basic minimum viable product working. Once I get into a state where the bulk of the features are supported, I’ll revisit some of the debt. This app is pretty simple, so that debt isn’t going to be a very big problem. Additionally, I’ve laid out the work ahead so that the debt is intentionally preventing other work from proceeding efficiently, so I can’t really move forward without attending to it.

More ahead…

ForeverList update: Added image support

I went a little nuts this evening and spent a few hours adding drag and drop image support to the app. Thankfully I’ve worked with images and dragging and dropping on the Mac before. In spite of that, it was still a little painful to get this working, mostly because of the pasteboard data format. I had some trouble getting the right NSURL data out of the pasteboard. I also had to work a bit to save the right image representation when writing the document to disk.

Anyway, I’ll have more info on how this all works later, but check out this real in-app screenshot.

The other cool thing is that all images are saved directly in the document package.