0

(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.

Community
  • 1
  • 1
Mojo66
  • 1,109
  • 12
  • 21

1 Answers1

0

I solved the problem by using the following dict in the -writeToUrl method:

NSDictionary *opts = @{NSSQLitePragmasOption: @{@"journal_mode":@"DELETE"}};
Mojo66
  • 1,109
  • 12
  • 21