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
NSFetchedResultsController
with 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
NSPersistentStoreCoordinator
class:+ (NSDictionary *)metadataForPersistentStoreOfType:(NSString *)storeType URL:(NSURL *)url error:(NSError **)error
Calling 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
NSPersistentStoreCoordinator
class, 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 **)error
Note 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
-wal
file 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-wal
file to the store file. This is actually the Core Data way to perform a checkpoint operation. On the other hand, if the-wal
file is not present, using this approach to add the store won't cause any exceptions, but the transactions recorded in the missing-wal
file will be lost.Bundle the main store file and the
-wal
file 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