New default journaling mode for Core Data SQLite stores in iOS 7 and OS X Mavericks
Q: My app backs up and restores a Core Data SQLite store by copying the store file. This works well on iOS 6.x and OS X Mountain Lion, but fails on iOS 7 and OS X Mavericks after updating to the latest SDK. Why is that?
A: The failure occurs because the default journaling mode for Core Data SQLite stores was changed to Write-Ahead Logging (WAL) in iOS 7 and OS X Mavericks. With the WAL mode, Core Data keeps the main store file untouched and appends transactions to a -wal file in the same location. After the Core Data context is saved, the -wal file is not deleted, and the data in that file is not merged to the store file either. Therefore, simply making copies of the store file will likely cause data loss and inconsistency.
If you create a Core Data stack from a store file which is generated by copying the main store file but not the corresponding -wal file, your app can fail in a number of ways, including:
Store data inconsistent with the existing cache. This happens when you use a
NSFetchedResultsControllerwith caching mechanism on. The inconsistency can trigger exceptions likeNSObjectInaccessibleException, or output messages complaining that the persistent cache does not match the current configuration.Failure to retrieve the meta data of the Core Data store using the following method of
NSPersistentStoreCoordinatorclass:+ (NSDictionary *)metadataForPersistentStoreOfType:(NSString *)storeType URL:(NSURL *)url error:(NSError **)errorCalling this method will cause a SQLite error of "unable to open database file".
To safely back up and restore a Core Data SQLite store, you can do the following:
Use the following method of
NSPersistentStoreCoordinatorclass, rather than file system APIs, to back up and restore the Core Data store:- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)errorNote that this is the option we recommend.
Change to rollback journaling mode when adding the store to a persistent store coordinator if you have to copy the store file. Listing 1 is the code showing how to do this:
Listing 1 Use rollback journaling mode when adding a persistent store
NSDictionary *options = @{NSSQLitePragmasOption:@{@"journal_mode":@"DELETE"}};if (! [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:options
error:&error]) {// error handling.
}
For a store that was loaded with the WAL mode, if both the main store file and the corresponding
-walfile exist, using rollback journaling mode to add the store to a persistent store coordinator will force Core Data to perform a checkpoint operation, which merges the data in the-walfile to the store file. This is actually the Core Data way to perform a checkpoint operation. On the other hand, if the-walfile is not present, using this approach to add the store won't cause any exceptions, but the transactions recorded in the missing-walfile will be lost.Bundle the main store file and the
-walfile into a document package and manipulate them as a single item.
For more information about the default journaling mode change, please see WWDC 2013 session 207 What's New in Core Data and iCloud.
NOTE: In iOS 6.x and Mountain Lion, the default is rollback journaling mode, in which Core Data creates a -journal file to temporarily store transactions, updates the main store file in place and deletes the -journal file after saving the context. The store file therefore contains the up-to-date database.
Document Revision History
| Date | Notes |
|---|---|
| 2014-01-29 | New document that describes the change to the default journaling mode for Core Data SQLite stores and the potential impacts. |
Copyright © 2014 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2014-01-29