Sunday, September 10, 2017

Periodic iCloud backup of SQLite database

Leave a Comment

Let me get this out of the way right now: yes, it was almost certainly a mistake to not use Core Data. However, I was new to iOS development when I made these decisions, and I had no idea I'd be hamstrung like this. Moreover, the app is intended to also run on Android (eventually), so I avoided platform-specific APIs wherever possible.

I have an iOS app that stores data in a local SQLite database file. The data stored in the file is provided by the user, so it's important that it be kept safe. I had plans to "do this later", and later is now here. I am quickly coming to the realization that it won't be as straightforward as I had hoped...

I now understand that it won't be possible to seamlessly synchronize data across devices, and I'm willing to accept that limitation until I manage to migrate to Core Data. However, in the meantime I'd at least like the SQLite database to be backed up periodically so users can feel safe using the app on a single device. I was thinking I would do this:

  • periodically (e.g. once a week) copy the SQLite file from local storage into cloud storage, thus ensuring it is backed up
  • when the app starts, if the local store is missing or corrupted but the file exists in the cloud storage, ask the user if they would like to copy it over

The biggest problem with this approach is that the user could run the app on multiple devices and therefore the data stored in iCloud could be from any one of those devices, but only one. To combat that, I thought I could just use a per-device, unique name for the file in cloud storage. I would generate this using UIDevice.identifierForVendor.

So my startup logic would be:

  1. Determine the unique name for the cloud file.
  2. Is the local file missing or corrupted, and if so, does the cloud file exist?

    2.1. Ask the user if they would like to restore from the cloud file. Make it really hard for them to say no because doing so will lose all their data.

    2.2. If they say yes, copy the cloud file to the local file storage.

  3. Open the local database file.

And running in the background I would occasionally copy the database file from local to cloud storage.

I would like to know whether this a sensible approach until I do Core Data integration. Also, are there any hidden "gotchas" that I'm perhaps missing?

UPDATE: as @TomHarrington pointed out in a comment, it turns out my database file is already sitting in /Documents, which is backed up to iTunes and any iCloud account. So my question morphs into this:

Should I simply ensure my database has a device-specific name so that it is not clobbered by the app running on another device connected to the same iCloud account?

1 Answers

Answers 1

I'm going to answer my question, since I ended up going down this path and finding a MASSIVE blocker. There is a bug in the UIDevice.identifierForVendor API that causes it to regenerate every time a new version of the app is installed! See here. This of course rules out using it as a device identifier. sigh

I think I'm SOL with that approach. Instead, I might generate a GUID on first execution and use that as my identifier. Problem is, I need to store that somewhere that isn't backed up to iCloud.

Ugh, I may just give up here and say my app can't be run on multiple devices until Core Data integration is done.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment