NSPersistentDocument provides way to configure store options on initial Save or on Save As

Originator:jacob
Number:rdar://19806400 Date Originated:11-Feb-2015 07:39 PM
Status:Open Resolved:
Product:OS X Product Version:Mac OS X 10.10.2 (14C109)
Classification:Enhancement Reproducible:Always
 
Summary:
While NSPersistentDocument has the method 
- configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error: it is only called when opening an existing persistent store. But it’s not used when saving a new document or during Save As. These are handled automatically by the class. The problem is that it’s not possible to set options for the store. 

Specifically, it makes a lot of sense for the SQLite stores to have the journal_mode = DELETE pragma set to avoid creating 3 files (WAL, SHM). Having 3 files for a document is a no-no! 

Steps to Reproduce:
In an application that uses NSPersistentDocument:

Override 
configurePersistentStoreCoordinatorForURL:ofType:modelConfiguration:storeOptions:error: and add to options: 
options[NSSQLitePragmasOption] = @{ @"journal_mode" : @"DELETE" };

Run application.
1. Create a new, untitled document.
2. Modify some data
3. Save it

Expected Results:
Save only creates one file for the document.

NSPersistentDocument should either consult the configure method (though it’s only used for opening, supposedly), or create a similar method for modifying options when save occurs. In any case, something is wrong here.

Actual Results:
Creates 3 files: document and two files needed for WAL.

Regression:
N/A

Notes:
Currently working around this by overriding:
- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError **)error {

    // Handle first saving and Saving As to set the correct options for SQLite because Core Data forgets our pragmas, stupid
    BOOL success;
    if (saveOperation == NSSaveAsOperation) {
        NSMutableDictionary *options = [NSMutableDictionary dictionary];
        options[NSSQLitePragmasOption] = @{ @"journal_mode" : @"DELETE" };
        options[NSMigratePersistentStoresAutomaticallyOption] = @YES;
        options[NSInferMappingModelAutomaticallyOption] = @YES;
        NSPersistentStoreCoordinator *coordinator = [[self managedObjectContext] persistentStoreCoordinator];
        NSPersistentStore *store;
        if (absoluteOriginalContentsURL) {
            store = [coordinator migratePersistentStore:[self persistentStore] toURL:absoluteURL options:[options copy] withType:NSSQLiteStoreType error:error];
            success = (store != nil);
        } else {
            store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:absoluteURL options:[options copy] error:error];
            success = (store != nil);
            if (success) {
                success = [[self managedObjectContext] save:error];
            }
        }
    } else {
        success = [super writeToURL:absoluteURL ofType:typeName forSaveOperation:saveOperation originalContentsURL:absoluteOriginalContentsURL error:error];
    }
    return success;
}

Comments

I think we are supposed to override managedObjectContext to implement this. When NSPersistentDocument needs the coordinator it gets it goes via this property.

By indiekiduk at Jan. 24, 2023, 6:20 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!