I have a document-based Cocoa app using CoreData which can import large amounts of data. Since this import takes some time I do it in the background, but since NSManagedObjectContext
is not thread save I used the persistentStoreCoordinator
of the managedObjectContext
of the document to create a new NSManagedObjectContext
in the background thread.
Now, when the import is finished I save the background managedObjectContext
to notify the document's main-thread managedObjectContext
of the changes and merge them. As far as I understand it, this is how one is supposed to do concurrency using CoreData.
But sometimes, the persistentStoreCoordinator
does not have a persistentStore
when I call [managedObjectContex save:]
which causes the save to fail and the app to crash. I'm using autosave and all (basically a mostly unmodifed NSPersistentDocument on OS X 10.8) so I assumed that I don't have to care about how it is saved and it would "just work".
Apparently, this is not the case.
I tried forcing an autosave operation, hoping that this would create a persistentStore by calling [self autosaveDocumentWithDelegate:self didAutosaveSelector:@selector(document:didAutosave:contextInfo:) contextInfo:nil];
at the end of windowControllerDidLoadNib:
in my document subclass, but this doesn't seem to change anything.
The delegate callback (- (void)document:(NSDocument *)document didAutosave:(BOOL)didAutosaveSuccessfully contextInfo:(void *)contextInfo
) actually states the autosave was successful although neither any of the fileURL or related accessors returns something non-nil nor a persistentStore has been created.
I also thought about calling -(BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError *__autoreleasing *)error
myself, but I don't know what URL to use to make it behave just like a normal autosave.
I checked backupFileURL
, fileURL
and autosavedContentsFileURL
but all of them are still nil at the end of windowControllerDidLoadNib:
. As a matter of fact, they are even nil after writeToURL:...
and configurePersistentStoreCoordinatorForURL:...
have been called, so I don't have a clue how to get a "correct" URL.
To better understand how and when a persistentStore is created I have set breakpoints in writeToURL:...
and configurePersistentStoreCoordinatorForURL:...
. I noticed that configurePersistentStoreCoordinatorForURL:
is called when the application looses frontmost status. But when I just create a new document and try importing something right after it was created (without first switching to another app to cause the persistentStore to be created) it crashes. If I switch to another app, the store is created and everything works fine.
By the way, the URL used for the persistentStore created this way is always somewhere in the temp directory.
Am I doing something wrong? Don't I have to call [managedObjectContext save:] to notify the other managedObjectContext of the changes?
How can I force the document to create its temporary persistentStore? Why doesn't the call to autosaveDocumentWithDelegate:...
actually save the document (and thus create a persistentStore
)?
Related:
- New project New Model NSPersistentDocument This NSPersistentStoreCoordinator has no persistent stores Similar problem but the solution there was to not save the context or present an error. I think I have to save the context to notify the second one of the changes and don't want to force the user to save the file manually (after all, that's what autosave is for).