Tag Archives: NSPersistentStore

How to migrate your persistent store from one location to another

Sometimes you need to change your NSPersistentStore file from one location to another. Or you want to add other options that the old store didn’t have (for example, add iCloud or turn an XML store into an SQLite store). In those cases you can migrate the current store.

Typically this is done by leaving the existing store as is, creating a new store with new properties. Then we’ll tell the NSPersistentStoreCoordinator about our plan, and he’ll swap out the store for us.

Here’s an example: I’ve created a Master/Detail Test App with Core Data and added a few records. All looks good. My persistent store was created by default like this – as provided by the template in AppDelegate.m:

Now I’d like to change the location of the store to a new URL. While I’m at it I could add a new options dictionary – but I won’t show that here, because I’m pretty sure you know how that works 😉

Here’s a method I’m using for the migration:

You can check if the migration has worked by writing out the URL before and after the migration. At this point the old store is no longer in use. If you’d like to go back it it at any time, simply perform another migration.

Demo Project

I’ve added a demo project on GitHub which demonstrates this:

How to test why your iCloud Core Data store was changed

When you’re using iCloud with Core Data you need to subscribe and react to the NSPersistentStoreCoordinatorStoresDidChange notification. This will tell you when Core Data was able to transition off the “fake” store and is using the “real” store. It will coincide with the log entry “Using local storage: 0”.

Sometimes you need to know why this has happened so you can react accordingly. Here’s how:

When you react to the above, bring the notification object into your even handler method. This will let you query its userInfo dictionary which will hold the key to why the stores have been changed:

Here we grab the NSPersistentStoreTransitionKeyType entry from the userInfo dictionary. It’s an NSNumber, enumerated to four keys. To test those with a switch statement I’m converting the NSNumber into an int.

Use this to check if an iCloud account has been changed, or if this is the first time an iCloud store has been started on the current device.

I’m explaining this as part of my screencast about using iCloud and Core Data:

How to swap out a store file in Core Data

You can switch out the NSPersistentStore file in your running Core Data app by first adding your new store file, then removing the previous one. Once done you must execute your fetch request again so that the new data is available.

Hot-swapping stores assumes both NSPersistentStore files are based on the same model. It’s like replacing a USB stick.

First let’s pass a reference of the Persistent Store Coordinator into the class you’d like to make the switch in. Based on the Xcode Utility Project, that’s MainViewController. The Core Data stack is already setup in the App Delegate, so we’ll pass a reference here:

Now that our MainViewController can use the coordinator, here’s how we can switch to a new file. I’m calling the current one store1 and the new one store2:

Test this by fetching your data before and after the swap. You don’t have to remove the second store, you can leave it in place if you’d like to fetch data from both stores. I’m not sure though what will happen if you add data – it may end up in both stores.

To check if your store file has changed, you can subscribe to this notification:

  • NSPersistentStoreCoordinatorStoresDidChangeNotification

Here’s an iOS Demo Project that I’ve put together:

How to avoid WAL files in Core Data

Since iOS 7 and OS X 10.9 the default journalling mode in SQLite Stores is WAL. In addition to the main store file you’ll find a WAL file with the same (or larger) size as the store file, and a less important SHM file.

Prior to this implementation it was easy to save the context, extract the store file and ship it with an app as a pre-made data store. That’s no longer possible, because by default all data changes are written to the WAL file and do not sync with the main store file.

This is not a problem if you’re not shipping a pre-made store file with your app, but if you do, then this “improvement” has just ruined your way of delivering prewritten data stores.

Lucky for us we can switch this entire WAL business off by passing an option when creating our NSPersistentStoreCoordinator:

This bizarre brackety @-intense statement is shorthand for an NSDictionary within a dictionary. Not so pretty on its own. In context, this statement can be passed as part of a default Core Data app when created from a template:

No options are passed by default. The same statement amended with the no-WAL option would look like this:

In addition you can pass other options like so:

Adding this will do away with WAL and let you use your persistent store file on its own again. At the time of writing, I know of no way to sync the changes from the WAL file back into the main store file.

How to use a provided store file with Core Data

Apple’s recommended method for dealing with “bring your own store files” for Core Data is to copy the store file into your app’s Documents directory, where it can be accessed for read and write queries.

However, if you don’t need to write to your store file, then you can also add a provided store file inside the main bundle. It would save some space on the user’s device.

Here’s the custom initialiser for NSPersistentStoreCoordinator, tweaked to show how to handle this:

Note that the option NSReadOnlyPersistentStoreOption:@YES is not strictly necessary.

How to use Core Data with multiple Store Files

Sometimes it can be useful to split your Core Data Store File across multiple files. For example, one file could live on the local file system, while the other could live in iCloud.

We can do this by telling the Xcode Model Editor to add more than one Configuration, each of which can be allocated certain Entities. Each Configuration can be configured to use a separate store file.

Consider this example code which is provided by the Xcode 4.6 templates to initiate the Persistent Store Coordinator:

This content is for members only.

Now you’ll work with two store files in the same Managed Object Context. This also means that whatever operation you call on the context (save for example) will be executed on both store files.

Demo Project

I’ve added a Demo Project to GitHub which demonstrates this in Mac OS X: