(My problem is somewhat similar to this one, except I'm not using an UndoManager, and the proposed solution doesn't work for me.)
My app imports data from a 3rd party app and stores it in memory until the user saves it. The import periodically save:'s to its own managedObjectContext on a background thread. This MOC uses the persistent store coordinator of it's parent NSPersistentDocument MOC. In order to avoid writing to a temp file on disk, a persistent store is added using the type NSInMemoryStoreType. When the user wants to actually save the data to a file on disk, migratePersistentStore withType:NSInMemoryStoreType is called in the writeToURL override in the NSPersistentDocument.
This all works fine as long as I use NSXMLStoreType for writing and reading (at //1 and //2 in the code below).
As soon as I switch to NSSQLiteStoreType, writing does produce a valid SQLite file with all the proper data in it, but reading back the file fails with the following error:
CoreData: error: Encountered exception I/O error for database at /a/b/c.dat. SQLite error code:14, 'unable to open database file' with userInfo {
NSFilePath = "/a/b/c.dat";
NSSQLiteErrorDomain = 14;
} while checking table name from store: <NSSQLiteConnection: 0x6080001e3300>
CoreData: error: -addPersistentStoreWithType:SQLite configuration:(null) URL:file:///a/b/c.dat options:{
NSMigratePersistentStoresAutomaticallyOption = 1;
NSReadOnlyPersistentStoreOption = 1;
} ... returned error Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened." UserInfo=0x60800006df40 {NSSQLiteErrorDomain=14, NSUnderlyingException=I/O error for database at /a/b/c.dat. SQLite error code:14, 'unable to open database file'} with userInfo dictionary {
NSSQLiteErrorDomain = 14;
NSUnderlyingException = "I/O error for database at /a/b/c.dat. SQLite error code:14, 'unable to open database file'";
Here is the relevant simplified code:
// NSPersistentDocument.m
- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError *__autoreleasing *)error {
NSError *err;
NSDictionary *opts = @{
NSMigratePersistentStoresAutomaticallyOption : @YES,// it doesn't matter if these options are set or not
NSReadOnlyPersistentStoreOption : @YES,
};
if (![self.managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType //1
configuration:nil
URL:absoluteURL
options:opts
error:&err])
{
return NO;
} else {
return YES;
}
}
- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError *__autoreleasing *)error {
NSDictionary *opts = @{
NSMigratePersistentStoresAutomaticallyOption : @YES,// it doesn't matter if these options are set or not
NSReadOnlyPersistentStoreOption : @YES,
};
NSError *err;
[self.managedObjectContext.persistentStoreCoordinator migratePersistentStore:self.managedObjectContext.persistentStoreCoordinator.persistentStores[0]
toURL:absoluteURL
options:opts
withType:NSSQLiteStoreType //2
error:&err];
return YES;
}
// ====================================
// NSOperation.m
- (void)main
{
[...]
self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.managedObjectContext.persistentStoreCoordinator = self.myDoc.managedObjectContext.persistentStoreCoordinator;
self.managedObjectContext.undoManager = nil;
[self.managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:nil
error:nil];
A typical database consists of 30k objects which takes ages to write and read when using XML so I do need to use the SQLite type.
Any suggestions are welcome.